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/apr system #369

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
c8553c1
wip: apy
Majorfi Jun 28, 2023
75f9fe7
fix: On Optimism it shows New on the list but 0 inside
karelianpie Jun 30, 2023
c53dba2
WIP
Majorfi Jun 29, 2023
558b234
fix: uri
Aug 16, 2023
3f4b02e
fix: boost
Aug 17, 2023
b7eec04
rebase
Majorfi Sep 6, 2023
f96ba47
feat: bump lib
Sep 14, 2023
89bc09f
feat: APR setup
Sep 21, 2023
a3ccfa0
fix: missing icon
Sep 21, 2023
b2f09a6
fix: invalid name
Sep 21, 2023
6de1691
fix: endpoint
Sep 21, 2023
e114f5c
fix: rebase
Oct 5, 2023
9f7c219
fix: dependencies
Oct 5, 2023
9e010ff
fix: zod retired
Oct 5, 2023
316ad52
feat: working on APY
Oct 5, 2023
93d1a7a
feat: rebase
Oct 5, 2023
24e4d48
fix: invalid schema
Oct 5, 2023
de86df1
fix: ordering
Oct 5, 2023
a27685a
fix: update dependencies
Oct 5, 2023
13cb98f
fix: minor UI adjustments
Oct 5, 2023
b2ce5a7
feat: by default all selected chains
Oct 5, 2023
9e919ed
fix: can unselect stuff
Oct 10, 2023
312db9a
fix: can unselect stuff
Oct 10, 2023
2144096
fix: truncate
Oct 10, 2023
834e509
fix: maybe fix invalid balance display
Oct 10, 2023
ea93ca3
fix: no zap possible & ui freeze
Oct 10, 2023
810cb1a
fix: responsiveness issue
Oct 10, 2023
912e758
fix: overflow
Oct 10, 2023
33e7d8e
fix: filters
Oct 10, 2023
f654639
fix: blockchain order
Oct 10, 2023
f3f3983
fix: underline
Oct 10, 2023
bd9a991
fix: lint
Oct 11, 2023
adddcef
fix: split all
Oct 11, 2023
217656a
fix: display historical when no forward
Oct 11, 2023
f761bde
feat: remove safeChainID usage
Oct 11, 2023
d374470
fix: more chain fixes
Oct 11, 2023
b41d3f6
fix: some elements
Oct 12, 2023
cbe0111
fix: add missing chains
Oct 12, 2023
6e502fb
fix: forknet balances
Oct 16, 2023
9c60d75
fix: forknet balances
Oct 16, 2023
ac09b2d
fix: forknet balances
Oct 16, 2023
33da362
fix: search all
Oct 16, 2023
eb92587
fix: use forknet
Oct 16, 2023
dd15821
wip: debt ratio checks
Oct 16, 2023
9ae42f8
feat: some useAsyncEffect
Oct 16, 2023
005a215
fix: useless multiple re-render
Oct 16, 2023
184cbee
fix: hide tooltip when 0 apr
Oct 16, 2023
99ecf5a
fix: invalid hooks
Oct 16, 2023
4b6534f
feat: use search query for vault list
Oct 17, 2023
a73fd9c
fix: missing arg and rename func
Oct 17, 2023
71f2a19
fix: use staking rewards too
Oct 17, 2023
07dc461
fix: 0.00 tooltip
Oct 17, 2023
bce898d
fix: remove chain check on boosted vaults
Oct 17, 2023
cb4561c
feat: use query args
Oct 17, 2023
88342a3
fix: search
Oct 17, 2023
5b7e86a
fix: remove log
Oct 17, 2023
c5f0137
fix: order
Oct 18, 2023
23ad84b
fix: order and APR display
Oct 18, 2023
3d34810
fix: add condition to hide when staking rewards is 0 or boost is 0
Oct 18, 2023
2082d04
fix: hide balancer category
Oct 18, 2023
fc395ed
fix: upd yarnlock
Oct 18, 2023
d785209
fix: lint
Oct 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module.exports = {
extends: ['./node_modules/@yearn-finance/web-lib/.eslintrc.cjs', 'plugin:@next/next/recommended', 'prettier'],
extends: [
'./node_modules/@yearn-finance/web-lib/.eslintrc.cjs',
'plugin:@next/next/recommended',
'prettier',
'plugin:react-hooks/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
Expand All @@ -24,6 +29,12 @@ module.exports = {
ImportDeclaration: {multiline: true, consistent: true},
ExportDeclaration: {multiline: true, minProperties: 3}
}
],
'react-hooks/exhaustive-deps': [
'warn',
{
additionalHooks: '^useAsyncTrigger$'
}
]
}
};
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"bracketSpacing": false,
"arrowParens": "avoid",
"bracketSameLine": true,
"singleAttributePerLine": true
"singleAttributePerLine": true,
"printWidth": 120
}
22 changes: 19 additions & 3 deletions apps/common/components/AmountInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ type TAmountInputProps = {
onMaxClick?: () => void;
};

export function AmountInput({amount, maxAmount, label, placeholder, legend, error, disabled, loading, onAmountChange, onLegendClick, onMaxClick}: TAmountInputProps): ReactElement {
export function AmountInput({
amount,
maxAmount,
label,
placeholder,
legend,
error,
disabled,
loading,
onAmountChange,
onLegendClick,
onMaxClick
}: TAmountInputProps): ReactElement {
let displayedAmount = amount.toString();
if (isZero(displayedAmount) && !disabled) {
displayedAmount = '';
Expand All @@ -31,7 +43,9 @@ export function AmountInput({amount, maxAmount, label, placeholder, legend, erro
{label && <p className={'mb-1 w-full truncate text-base text-neutral-600'}>{label}</p>}
<div className={'relative flex w-full items-center justify-center'}>
<input
className={`h-10 w-full p-2 font-mono text-base font-normal outline-none ${maxAmount && !disabled ? 'pr-12' : null} ${
className={`h-10 w-full p-2 font-mono text-base font-normal outline-none ${
maxAmount && !disabled ? 'pr-12' : null
} ${
error ? 'border border-solid border-[#EA5204] focus:border-[#EA5204]' : 'border-0 border-none'
} ${disabled ? 'bg-neutral-300 text-neutral-600' : 'bg-neutral-0'}`}
type={'number'}
Expand All @@ -45,7 +59,9 @@ export function AmountInput({amount, maxAmount, label, placeholder, legend, erro
<Renderable shouldRender={!!maxAmount && !disabled}>
<button
onClick={onMaxClick ? (): void => onMaxClick() : undefined}
className={'absolute right-2 ml-2 h-6 cursor-pointer border-none bg-neutral-900 px-2 py-1 text-xs text-neutral-0 transition-colors hover:bg-neutral-700'}>
className={
'absolute right-2 ml-2 h-6 cursor-pointer border-none bg-neutral-900 px-2 py-1 text-xs text-neutral-0 transition-colors hover:bg-neutral-700'
}>
{'Max'}
</button>
</Renderable>
Expand Down
7 changes: 5 additions & 2 deletions apps/common/components/AppHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ function LogoPopover(): ReactElement {
leave={'transition ease-in duration-150'}
leaveFrom={'opacity-100 translate-y-0'}
leaveTo={'opacity-0 translate-y-1'}>
<Popover.Panel className={'absolute left-1/2 z-10 mt-6 w-80 -translate-x-1/2 px-4 pt-4 sm:px-0 md:w-96'}>
<Popover.Panel
className={'absolute left-1/2 z-10 mt-6 w-80 -translate-x-1/2 px-4 pt-4 sm:px-0 md:w-96'}>
<div className={'overflow-hidden border border-neutral-200 shadow-lg'}>
<div className={'relative grid grid-cols-2 bg-neutral-0 md:grid-cols-3'}>
{[...Object.values(APPS), YETH]
Expand All @@ -100,7 +101,9 @@ function LogoPopover(): ReactElement {
onClick={(): void => set_isShowing(false)}>
<div
onClick={(): void => set_isShowing(false)}
className={'flex cursor-pointer flex-col items-center p-4 transition-colors hover:bg-neutral-200'}>
className={
'flex cursor-pointer flex-col items-center p-4 transition-colors hover:bg-neutral-200'
}>
<div>{cloneElement(icon)}</div>
<div className={'pt-2 text-center'}>
<b className={'text-base'}>{name}</b>
Expand Down
63 changes: 52 additions & 11 deletions apps/common/components/BalanceReminderPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import {Popover, Transition} from '@headlessui/react';
import {captureException} from '@sentry/nextjs';
import {Renderable} from '@yearn-finance/web-lib/components/Renderable';
import {useWeb3} from '@yearn-finance/web-lib/contexts/useWeb3';
import {useChainID} from '@yearn-finance/web-lib/hooks/useChainID';
import {IconAddToMetamask} from '@yearn-finance/web-lib/icons/IconAddToMetamask';
import {IconCross} from '@yearn-finance/web-lib/icons/IconCross';
import {IconWallet} from '@yearn-finance/web-lib/icons/IconWallet';
import {toAddress, truncateHex} from '@yearn-finance/web-lib/utils/address';
import {cl} from '@yearn-finance/web-lib/utils/cl';
import {formatAmount} from '@yearn-finance/web-lib/utils/format.number';
import {ImageWithFallback} from '@common/components/ImageWithFallback';
import {useWallet} from '@common/contexts/useWallet';
import {useYearn} from '@common/contexts/useYearn';
import {useBalance} from '@common/hooks/useBalance';
import {IconQuestion} from '@common/icons/IconQuestion';

import type {ReactElement} from 'react';
import type {TAddress} from '@yearn-finance/web-lib/types';
Expand All @@ -28,10 +29,14 @@ type TBalanceReminderElement = {

function TokenItem({element}: {element: TBalanceReminderElement}): ReactElement {
const {provider} = useWeb3();
const {safeChainID} = useChainID();
const balance = useBalance({address: element.address, chainID: element.chainID});

async function addTokenToMetamask(address: TAddress, symbol: string, decimals: number, image: string): Promise<void> {
async function addTokenToMetamask(
address: TAddress,
symbol: string,
decimals: number,
image: string
): Promise<void> {
if (!provider) {
return;
}
Expand Down Expand Up @@ -63,7 +68,9 @@ function TokenItem({element}: {element: TBalanceReminderElement}): ReactElement
width={32}
height={32}
quality={90}
src={`${process.env.BASE_YEARN_ASSETS_URI}/${safeChainID}/${toAddress(element.address)}/logo-128.png`}
src={`${process.env.BASE_YEARN_ASSETS_URI}/${element.chainID}/${toAddress(
element.address
)}/logo-128.png`}
/>
</div>
<span className={'ml-2'}>{element.symbol}</span>
Expand All @@ -78,10 +85,14 @@ function TokenItem({element}: {element: TBalanceReminderElement}): ReactElement
element.address,
element.symbol,
element.decimals,
`${process.env.BASE_YEARN_ASSETS_URI}/${safeChainID}/${toAddress(element.address)}/logo-128.png`
`${process.env.BASE_YEARN_ASSETS_URI}/${element.chainID}/${toAddress(
element.address
)}/logo-128.png`
);
}}
className={'ml-4 h-4 w-4 cursor-pointer text-neutral-400 transition-colors hover:text-neutral-900'}
className={
'ml-4 h-4 w-4 cursor-pointer text-neutral-400 transition-colors hover:text-neutral-900'
}
/>
</span>
</span>
Expand All @@ -90,7 +101,7 @@ function TokenItem({element}: {element: TBalanceReminderElement}): ReactElement
}

export function BalanceReminderPopover(): ReactElement {
const {balances: tokens, isLoading} = useWallet();
const {balances: tokens, isLoading, triggerForknetBalances, shouldUseForknetBalances} = useWallet();
const {address, ens, isActive, onDesactivate} = useWeb3();
const {vaults} = useYearn();

Expand Down Expand Up @@ -153,16 +164,46 @@ export function BalanceReminderPopover(): ReactElement {
leave={'transition ease-in duration-150'}
leaveFrom={'opacity-100 translate-y-0'}
leaveTo={'opacity-0 translate-y-1'}>
<Popover.Panel className={'yearn--shadow absolute right-0 top-6 z-[1000] mt-3 w-screen max-w-xs md:-right-4 md:top-4'}>
<Popover.Panel
className={
'yearn--shadow absolute right-0 top-6 z-[1000] mt-3 w-screen max-w-xs md:-right-4 md:top-4'
}>
<div className={'overflow-hidden'}>
<div className={'relative bg-neutral-0 p-0'}>
<div className={'flex items-center justify-center border-b border-neutral-300 py-4 text-center'}>
<b>{isActive && address && ens ? ens : isActive && address ? truncateHex(address, 5) : 'Connect wallet'}</b>
<div
className={cl(
'absolute left-4 top-4 opacity-0 transition-colors hover:opacity-100',
shouldUseForknetBalances ? 'opacity-100' : 'opacity-0'
)}>
<button
onClick={(): void => {
// Special command to enable dev forknet balances
triggerForknetBalances();
}}
className={
'flex h-6 w-6 items-center justify-center rounded-full bg-neutral-200/50'
}>
<IconQuestion className={'h-4 w-4 text-neutral-600'} />
</button>
</div>
<div
className={
'flex items-center justify-center border-b border-neutral-300 py-4 text-center'
}>
<b>
{isActive && address && ens
? ens
: isActive && address
? truncateHex(address, 5)
: 'Connect wallet'}
</b>
</div>
<div className={'absolute right-4 top-4'}>
<button
onClick={onDesactivate}
className={'flex h-6 w-6 items-center justify-center rounded-full bg-neutral-200/50'}>
className={
'flex h-6 w-6 items-center justify-center rounded-full bg-neutral-200/50'
}>
<IconCross className={'h-4 w-4 text-neutral-600'} />
</button>
</div>
Expand Down
28 changes: 23 additions & 5 deletions apps/common/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ const DropdownOption = (option: TDropdownOption): ReactElement => {
)}
<div>
<p className={`font-normal text-neutral-900 ${icon ? 'pl-2' : 'pl-0'}`}>{label}</p>
{description && <p className={`text-xxs font-normal text-neutral-600 ${icon ? 'pl-2' : 'pl-0'}`}>{description}</p>}
{description && (
<p className={`text-xxs font-normal text-neutral-600 ${icon ? 'pl-2' : 'pl-0'}`}>
{description}
</p>
)}
</div>
</div>
)}
Expand Down Expand Up @@ -76,12 +80,22 @@ export type TDropdownProps = {
className?: string;
};

export const Dropdown = ({selected, options, onChange, label, legend, isDisabled, className}: TDropdownProps): ReactElement => {
export const Dropdown = ({
selected,
options,
onChange,
label,
legend,
isDisabled,
className
}: TDropdownProps): ReactElement => {
const [isOpen, set_isOpen] = useThrottledState(false, 400);
const [search, set_search] = useState('');

const isSearching = search !== '';
const filteredOptions = isSearching ? options.filter(({label}): boolean => label.toLowerCase().includes(search.toLowerCase())) : options;
const filteredOptions = isSearching
? options.filter(({label}): boolean => label.toLowerCase().includes(search.toLowerCase()))
: options;

return (
<div className={className}>
Expand Down Expand Up @@ -136,7 +150,9 @@ export const Dropdown = ({selected, options, onChange, label, legend, isDisabled
isDisabled ? 'text-neutral-600' : 'text-neutral-900'
)}>
<Combobox.Input
className={'w-full cursor-default overflow-x-scroll border-none bg-transparent p-0 outline-none scrollbar-none'}
className={
'w-full cursor-default overflow-x-scroll border-none bg-transparent p-0 outline-none scrollbar-none'
}
displayValue={(option?: TDropdownOption): string => option?.label ?? '-'}
spellCheck={false}
onChange={(event): void => {
Expand All @@ -151,7 +167,9 @@ export const Dropdown = ({selected, options, onChange, label, legend, isDisabled
<div className={'absolute right-2 md:right-3'}>
<IconChevron
aria-hidden={'true'}
className={`h-6 w-6 transition-transform ${isOpen ? '-rotate-180' : 'rotate-0'}`}
className={`h-6 w-6 transition-transform ${
isOpen ? '-rotate-180' : 'rotate-0'
}`}
/>
</div>
</Combobox.Button>
Expand Down
27 changes: 21 additions & 6 deletions apps/common/components/GaugeDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ function DropdownItem({option}: TDropdownGaugeItemProps): ReactElement {
<div
data-active={active}
className={'yearn--dropdown-menu-item w-full hover:bg-neutral-0/40'}>
<div className={'h-6 w-6 flex-none rounded-full'}>{option?.icon ? cloneElement(option.icon) : null}</div>
<div className={'h-6 w-6 flex-none rounded-full'}>
{option?.icon ? cloneElement(option.icon) : null}
</div>
<div className={'flex w-full flex-row items-center justify-between'}>
<p className={`${option.icon ? 'pl-2' : 'pl-0'} font-normal text-neutral-900`}>{option.label}</p>
<p className={`${option.icon ? 'pl-2' : 'pl-0'} font-normal text-neutral-900`}>
{option.label}
</p>
<p className={`${option.icon ? 'pl-2' : 'pl-0'} text-xs font-normal text-neutral-600`}>
{`APY ${formatPercent((option?.value?.APY || 0) * 100, 2, 2, 500)}`}
</p>
Expand Down Expand Up @@ -90,16 +94,27 @@ export function Dropdown({options, selected, onSelect, placeholder = ''}: TDropd
<>
<Combobox.Button
onClick={(): void => set_isOpen(!isOpen)}
className={'flex h-10 w-full items-center justify-between bg-neutral-0 p-2 text-base text-neutral-900 md:px-3'}>
className={
'flex h-10 w-full items-center justify-between bg-neutral-0 p-2 text-base text-neutral-900 md:px-3'
}>
<div className={'relative flex flex-row items-center'}>
<div
key={selected?.label}
className={'h-6 w-6 flex-none rounded-full'}>
{selected?.icon ? cloneElement(selected.icon) : <div className={'h-6 w-6 flex-none rounded-full bg-neutral-500'} />}
{selected?.icon ? (
cloneElement(selected.icon)
) : (
<div className={'h-6 w-6 flex-none rounded-full bg-neutral-500'} />
)}
</div>
<p className={'max-w-[90%] overflow-x-hidden text-ellipsis whitespace-nowrap pl-2 font-normal text-neutral-900 scrollbar-none md:max-w-full'}>
<p
className={
'max-w-[90%] overflow-x-hidden text-ellipsis whitespace-nowrap pl-2 font-normal text-neutral-900 scrollbar-none md:max-w-full'
}>
<Combobox.Input
className={'w-full cursor-default overflow-x-scroll border-none bg-transparent p-0 outline-none scrollbar-none'}
className={
'w-full cursor-default overflow-x-scroll border-none bg-transparent p-0 outline-none scrollbar-none'
}
displayValue={(option: TDropdownGaugeOption): string => option.label}
placeholder={placeholder}
spellCheck={false}
Expand Down
5 changes: 4 additions & 1 deletion apps/common/components/HeroTimer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ export function HeroTimer({endTime}: TProps): ReactElement {
<div className={'md:mb-0 md:mt-16'}>
<div className={'mx-auto flex w-full max-w-6xl flex-col items-center justify-center'}>
<div className={'mt-10 w-[300px] md:w-full'}>
<div className={'flex w-full items-center justify-center text-center text-4xl font-bold uppercase text-neutral-900 md:text-8xl'}>
<div
className={
'flex w-full items-center justify-center text-center text-4xl font-bold uppercase text-neutral-900 md:text-8xl'
}>
<b
className={'font-number'}
suppressHydrationWarning>
Expand Down
24 changes: 21 additions & 3 deletions apps/common/components/ListHead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,23 @@ export type TListHead = {
onSort: (sortBy: string, sortDirection: TSortDirection) => void;
};

export function ListHead({items, dataClassName, wrapperClassName, tokenClassName, sortBy, sortDirection, onSort}: TListHead): ReactElement {
export function ListHead({
items,
dataClassName,
wrapperClassName,
tokenClassName,
sortBy,
sortDirection,
onSort
}: TListHead): ReactElement {
const toggleSortDirection = (newSortBy: string): TSortDirection => {
return sortBy === newSortBy ? (sortDirection === '' ? 'desc' : sortDirection === 'desc' ? 'asc' : 'desc') : 'desc';
return sortBy === newSortBy
? sortDirection === ''
? 'desc'
: sortDirection === 'desc'
? 'asc'
: 'desc'
: 'desc';
};

const renderChevron = useCallback(
Expand All @@ -33,7 +47,11 @@ export function ListHead({items, dataClassName, wrapperClassName, tokenClassName
if (shouldSortBy && sortDirection === 'asc') {
return <IconChevronPlain className={'yearn--sort-chevron rotate-180'} />;
}
return <IconChevronPlain className={'yearn--sort-chevron--off text-neutral-300 group-hover:text-neutral-500'} />;
return (
<IconChevronPlain
className={'yearn--sort-chevron--off text-neutral-300 group-hover:text-neutral-500'}
/>
);
},
[sortDirection]
);
Expand Down
Loading
Loading