Skip to content

Commit

Permalink
feat: Checkbox to not stake into OP boosted vaults (#345)
Browse files Browse the repository at this point in the history
* refactor(Switch): Remove unknown

* feat: Checkbox to not stake into OP boosted vaults

* refactor: Styling

* chore: Bump web-lib

* feat: Show stake automatically only for OP Boosted Vaults
  • Loading branch information
karelianpie authored Sep 18, 2023
1 parent 3f20a06 commit 95cbe08
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 30 deletions.
25 changes: 16 additions & 9 deletions apps/common/components/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
import {useState} from 'react';
import {Switch as HeadlessSwitch} from '@headlessui/react';
import {cl} from '@yearn-finance/web-lib/utils/cl';

import type {ReactElement} from 'react';
import type {KeyboardEvent, ReactElement} from 'react';

type TSwitch = {
isEnabled: boolean;
onSwitch?: React.Dispatch<React.SetStateAction<boolean>>;
onSwitch?: () => void;
};

export function Switch(props: TSwitch): ReactElement {
const {isEnabled, onSwitch} = props;
const [isEnabledState, set_isEnabledState] = useState(isEnabled);

function safeOnSwitch(): void {
if (onSwitch) {
onSwitch(!isEnabled);
} else {
set_isEnabledState(!isEnabledState);
onSwitch ? onSwitch() : set_isEnabledState(!isEnabledState);
}

const isChecked = onSwitch ? isEnabled : isEnabledState;

function handleOnKeyDown({key}: KeyboardEvent<HTMLButtonElement>): void | null {
if (key !== 'Enter') {
return;
}

safeOnSwitch();
}

return (
<div>
<HeadlessSwitch
checked={onSwitch ? isEnabled : isEnabledState}
checked={isChecked}
onChange={safeOnSwitch}
onKeyDown={({keyCode}: {keyCode: number}): unknown => keyCode === 13 ? safeOnSwitch() : null}
onKeyDown={handleOnKeyDown}
className={'yearn--next-switch'}>
<span className={'sr-only'}>{'Use setting'}</span>
<div
aria-hidden={'true'}
className={(onSwitch ? isEnabled : isEnabledState) ? 'translate-x-[14px]' : 'translate-x-0'} />
className={cl(isChecked ? 'translate-x-[14px]' : 'translate-x-0')} />
</HeadlessSwitch>
</div>
);
Expand Down
11 changes: 9 additions & 2 deletions apps/common/contexts/useYearn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ export type TYearnContext = {
isLoadingVaultList: boolean,
zapSlippage: number,
zapProvider: TSolver,
isStakingOpBoostedVaults: boolean,
mutateVaultList: KeyedMutator<TYDaemonVaults>,
set_zapSlippage: (value: number) => void
set_zapProvider: (value: TSolver) => void
set_isStakingOpBoostedVaults: (value: boolean) => void
}

const YearnContext = createContext<TYearnContext>({
Expand All @@ -55,10 +57,12 @@ const YearnContext = createContext<TYearnContext>({
isLoadingVaultList: false,
zapSlippage: 0.1,
zapProvider: Solver.enum.Cowswap,
isStakingOpBoostedVaults: true,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mutateVaultList: (): any => undefined,
set_zapSlippage: (): void => undefined,
set_zapProvider: (): void => undefined
set_zapProvider: (): void => undefined,
set_isStakingOpBoostedVaults: (): void => undefined
});

export const YearnContextApp = memo(function YearnContextApp({children}: { children: ReactElement }): ReactElement {
Expand All @@ -68,6 +72,7 @@ export const YearnContextApp = memo(function YearnContextApp({children}: { child
const {address, currentPartner} = useWeb3();
const [zapSlippage, set_zapSlippage] = useLocalStorage<number>('yearn.fi/zap-slippage', DEFAULT_SLIPPAGE);
const [zapProvider, set_zapProvider] = useLocalStorage<TSolver>('yearn.fi/zap-provider', Solver.enum.Cowswap);
const [isStakingOpBoostedVaults, set_isStakingOpBoostedVaults] = useLocalStorage<boolean>('yearn.fi/staking-op-boosted-vaults', true);

useEffect((): void => {
if (result?.error?.code === 'ERR_NETWORK') {
Expand Down Expand Up @@ -165,12 +170,14 @@ export const YearnContextApp = memo(function YearnContextApp({children}: { child
set_zapSlippage,
zapProvider,
set_zapProvider,
isStakingOpBoostedVaults,
set_isStakingOpBoostedVaults,
vaults: vaultsObject,
vaultsMigrations: vaultsMigrationsObject,
vaultsRetired: vaultsRetiredObject,
isLoadingVaultList,
mutateVaultList
}), [currentPartner?.id, pricesUpdated, tokens, earned, zapSlippage, set_zapSlippage, zapProvider, set_zapProvider, vaultsObject, vaultsMigrationsObject, isLoadingVaultList, mutateVaultList, vaultsRetiredObject]);
}), [currentPartner?.id, pricesUpdated, tokens, earned, zapSlippage, set_zapSlippage, zapProvider, set_zapProvider, isStakingOpBoostedVaults, set_isStakingOpBoostedVaults, vaultsObject, vaultsMigrationsObject, isLoadingVaultList, mutateVaultList, vaultsRetiredObject]);

return (
<YearnContext.Provider value={contextValue}>
Expand Down
45 changes: 33 additions & 12 deletions apps/vaults/components/SettingsPopover.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
import {Fragment, useMemo} from 'react';
import {Popover, Transition} from '@headlessui/react';
import {isSolverDisabled} from '@vaults/contexts/useSolver';
import {useStakingRewards} from '@vaults/contexts/useStakingRewards';
import {Renderable} from '@yearn-finance/web-lib/components/Renderable';
import {IconSettings} from '@yearn-finance/web-lib/icons/IconSettings';
import {Switch} from '@common/components/Switch';
import {useYearn} from '@common/contexts/useYearn';
import {Solver} from '@common/schemas/yDaemonTokenListBalances';

import type {ReactElement} from 'react';
import type {TSolver} from '@common/schemas/yDaemonTokenListBalances';
import type {TYDaemonVault} from '@common/schemas/yDaemonVaultsSchemas';

type TSettingPopover = {
chainID: number
vault: TYDaemonVault
}
export function SettingsPopover({chainID}: TSettingPopover): ReactElement {
const {zapProvider, set_zapProvider, zapSlippage, set_zapSlippage} = useYearn();

function Label({children}: {children: string}): ReactElement {
return <label htmlFor={'zapProvider'} className={'font-bold text-neutral-900'}>{children}</label>;
}

export function SettingsPopover({vault}: TSettingPopover): ReactElement {
const {zapProvider, set_zapProvider, zapSlippage, set_zapSlippage, isStakingOpBoostedVaults, set_isStakingOpBoostedVaults} = useYearn();
const {stakingRewardsByVault} = useStakingRewards();

const {address, chainID} = vault;
const hasStakingRewards = !!stakingRewardsByVault?.[address];

const currentZapProvider = useMemo((): TSolver => {
if (chainID !== 1 && zapProvider === 'Cowswap') {
Expand Down Expand Up @@ -41,8 +53,8 @@ export function SettingsPopover({chainID}: TSettingPopover): ReactElement {
<Popover.Panel className={'absolute right-0 top-6 z-[1000] mt-3 w-screen max-w-xs md:-right-4 md:top-4'}>
<div className={'yearn--shadow'}>
<div className={'relative bg-neutral-0 p-4'}>
<div className={'mb-7 flex flex-col space-y-1'}>
<label htmlFor={'zapProvider'} className={'text-neutral-900'}>{'Zap Provider'}</label>
<div className={'mb-6 flex flex-col space-y-1'}>
<Label>{'Zap Provider'}</Label>
<select
id={'zapProvider'}
onChange={(e): void => set_zapProvider(e.target.value as TSolver)}
Expand Down Expand Up @@ -80,7 +92,7 @@ export function SettingsPopover({chainID}: TSettingPopover): ReactElement {
</legend>
</Renderable>
<Renderable shouldRender={currentZapProvider === Solver.enum.Wido}>
<legend className={'text-xs italic text-neutral-500'}>
<legend className={'ml-2 text-xs text-neutral-500'}>
{'Submit an order via'}&nbsp;
<a
className={'underline'}
Expand All @@ -96,12 +108,8 @@ export function SettingsPopover({chainID}: TSettingPopover): ReactElement {
<legend>&nbsp;</legend>
</Renderable>
</div>
<div>
<label
htmlFor={'slippageTolerance'}
className={'text-neutral-900'}>
{'Slippage tolerance'}
</label>
<div className={'flex flex-col space-y-1'}>
<Label>{'Slippage'}</Label>
<div className={'mt-1 flex flex-row space-x-2'}>
<button
onClick={(): void => set_zapSlippage(1)}
Expand Down Expand Up @@ -129,6 +137,19 @@ export function SettingsPopover({chainID}: TSettingPopover): ReactElement {
</div>
</div>
</div>
{hasStakingRewards ?
<div className={'mt-6'}>
<Label>{'OP Boosted Vaults'}</Label>
<div className={'mt-1 flex flex-row space-x-2'}>
<div className={'flex grow items-center justify-between'}>
<p className={'mr-2'}>{'Stake automatically'}</p>
<Switch
isEnabled={isStakingOpBoostedVaults}
onSwitch={(): void => set_isStakingOpBoostedVaults(!isStakingOpBoostedVaults)} />
</div>

</div>
</div> : null}
</div>
</div>
</Popover.Panel>
Expand Down
2 changes: 1 addition & 1 deletion apps/vaults/components/details/VaultActionsTabsWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export function VaultActionsTabsWrapper({currentVault}: {currentVault: TYDaemonV
</div>

<div className={'flex flex-row items-center justify-end space-x-2 pb-0 md:pb-4 md:last:space-x-4'}>
<SettingsPopover chainID={currentVault.chainID} />
<SettingsPopover vault={currentVault} />
</div>
</div>
<div className={'-mt-0.5 h-0.5 w-full bg-neutral-300'} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {isEth} from '@yearn-finance/web-lib/utils/isEth';
import {isZero} from '@yearn-finance/web-lib/utils/isZero';
import {defaultTxStatus} from '@yearn-finance/web-lib/utils/web3/transaction';
import {useWallet} from '@common/contexts/useWallet';
import {useYearn} from '@common/contexts/useYearn';
import {Solver} from '@common/schemas/yDaemonTokenListBalances';

import type {ReactElement} from 'react';
Expand All @@ -22,6 +23,7 @@ export function VaultDetailsQuickActionsButtons(): ReactElement {
const {refresh} = useWallet();
const {refresh: refreshZapBalances} = useWalletForZap();
const {address, provider} = useWeb3();
const {isStakingOpBoostedVaults} = useYearn();
const {safeChainID} = useChainID();
const [txStatusApprove, set_txStatusApprove] = useState(defaultTxStatus);
const [txStatusExecuteDeposit, set_txStatusExecuteDeposit] = useState(defaultTxStatus);
Expand Down Expand Up @@ -164,7 +166,7 @@ export function VaultDetailsQuickActionsButtons(): ReactElement {
}

if (isDepositing || currentSolver === Solver.enum.InternalMigration) {
if (currentSolver === Solver.enum.OptimismBooster) {
if (currentSolver === Solver.enum.OptimismBooster && isStakingOpBoostedVaults) {
return (
<Button
onClick={async (): Promise<void> => onExecuteDeposit(set_txStatusExecuteDeposit, onSuccess)}
Expand Down
8 changes: 5 additions & 3 deletions apps/vaults/contexts/useActionFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export function ActionFlowContextApp({children, currentVault}: {children: ReactN
const {balances, balancesNonce} = useWallet();
const {chainID, safeChainID} = useChainID();
const {balances: zapBalances, tokensList} = useWalletForZap();
const {zapProvider} = useYearn();
const {zapProvider, isStakingOpBoostedVaults} = useYearn();
const {stakingRewardsByVault} = useStakingRewards();
const hasStakingRewards = !!stakingRewardsByVault[currentVault.address];
const [possibleOptionsFrom, set_possibleOptionsFrom] = useState<TDropdownOption[]>([]);
Expand Down Expand Up @@ -198,7 +198,9 @@ export function ActionFlowContextApp({children, currentVault}: {children: ReactN

const currentSolver = useMemo((): TSolver => {
const isUnderlyingToken = toAddress(actionParams?.selectedOptionFrom?.value) === toAddress(currentVault.token.address);
if (hasStakingRewards && isDepositing && isUnderlyingToken) {

// Only use OptimismBooster if the user chose to stake automatically
if ((hasStakingRewards && isStakingOpBoostedVaults) && isDepositing && isUnderlyingToken) {
return Solver.enum.OptimismBooster;
}

Expand Down Expand Up @@ -226,7 +228,7 @@ export function ActionFlowContextApp({children, currentVault}: {children: ReactN
return Solver.enum.PartnerContract;
}
return Solver.enum.Vanilla;
}, [actionParams?.selectedOptionFrom?.value, actionParams?.selectedOptionFrom?.solveVia?.length, actionParams?.selectedOptionTo?.value, actionParams?.selectedOptionTo?.solveVia?.length, currentVault.token.address, currentVault.address, currentVault?.migration?.available, currentVault?.migration?.address, hasStakingRewards, isDepositing, safeChainID, isUsingPartnerContract, zapProvider]);
}, [actionParams?.selectedOptionFrom?.value, actionParams?.selectedOptionFrom?.solveVia?.length, actionParams?.selectedOptionTo?.value, actionParams?.selectedOptionTo?.solveVia?.length, currentVault.token.address, currentVault.address, currentVault?.migration?.available, currentVault?.migration?.address, hasStakingRewards, isDepositing, safeChainID, isUsingPartnerContract, zapProvider, isStakingOpBoostedVaults]);

const onSwitchSelectedOptions = useCallback((nextFlow = Flow.Switch): void => {
balancesNonce;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@rainbow-me/rainbowkit": "^1.0.10",
"@wagmi/chains": "^1.8.0",
"@wagmi/core": "^1.4.1",
"@yearn-finance/web-lib": "^3.0.37",
"@yearn-finance/web-lib": "3.0.37",
"axios": "^1.5.0",
"dayjs": "^1.11.9",
"eslint-plugin-react-hooks": "^4.6.0",
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3564,7 +3564,7 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==

"@yearn-finance/web-lib@^3.0.37":
"@yearn-finance/[email protected]":
version "3.0.37"
resolved "https://registry.yarnpkg.com/@yearn-finance/web-lib/-/web-lib-3.0.37.tgz#e2e8679e2acbcc5041aeb13f9338a4b85aa3d466"
integrity sha512-ocQFwO2QPiK9HIbtkYnqWIVUGRbsAQ/WsYcHKElvc4IUUSpxGm537eFCwwWApLaYXtHIRvb1LHafja+62DDhbg==
Expand Down

1 comment on commit 95cbe08

@vercel
Copy link

@vercel vercel bot commented on 95cbe08 Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.