diff --git a/apps/common/utils/constants.tsx b/apps/common/utils/constants.tsx index d7cd187af..13a300111 100644 --- a/apps/common/utils/constants.tsx +++ b/apps/common/utils/constants.tsx @@ -13,6 +13,7 @@ import type {TApp} from '@common/types/category'; export const DEFAULT_SLIPPAGE = 0.5; export const DEFAULT_MAX_LOSS = 1n; export const YGAUGES_ZAP_ADDRESS = toAddress('0x1104215963474A0FA0Ac09f4E212EF7282F2A0bC'); //Address of the zap to deposit & stake in the veYFI gauge +export const VEYFI_ADDRESS = toAddress('0x90c1f9220d90d3966FbeE24045EDd73E1d588aD5'); //Address of the veYFI contract export const V3_STAKING_ZAP_ADDRESS: TNDict = { [mainnet.id]: toAddress('0x5435cA9b6D9468A6e0404a4819D39ebbF036DB1E'), [arbitrum.id]: toAddress('0x1E789A49902370E5858Fae67518aF49d8deA299c') diff --git a/apps/vaults/contexts/useActionFlow.tsx b/apps/vaults/contexts/useActionFlow.tsx index 241b5b5eb..1d9fdcf20 100644 --- a/apps/vaults/contexts/useActionFlow.tsx +++ b/apps/vaults/contexts/useActionFlow.tsx @@ -1,5 +1,6 @@ import {createContext, useCallback, useContext, useEffect, useMemo, useReducer, useState} from 'react'; import {useRouter} from 'next/router'; +import {useReadContract} from 'wagmi'; import {useWeb3} from '@builtbymom/web3/contexts/useWeb3'; import {useTokenList} from '@builtbymom/web3/contexts/WithTokenList'; import {useAsyncTrigger} from '@builtbymom/web3/hooks/useAsyncTrigger'; @@ -17,6 +18,7 @@ import {retrieveConfig} from '@builtbymom/web3/utils/wagmi'; import {useMountEffect} from '@react-hookz/web'; import {Solver} from '@vaults/types/solvers'; import {VAULT_V3_ABI} from '@vaults/utils/abi/vaultV3.abi'; +import {VEYFI_ABI} from '@vaults/utils/abi/veYFI.abi'; import {setZapOption} from '@vaults/utils/zapOptions'; import {readContracts, serialize, simulateContract} from '@wagmi/core'; import {VAULT_ABI} from '@yearn-finance/web-lib/utils/abi/vault.abi'; @@ -24,6 +26,7 @@ import { ETH_TOKEN_ADDRESS, LPYCRV_TOKEN_ADDRESS, OPT_WETH_TOKEN_ADDRESS, + VEYFI_ADDRESS, WETH_TOKEN_ADDRESS, WFTM_TOKEN_ADDRESS, YVWETH_ADDRESS, @@ -403,6 +406,19 @@ export function ActionFlowContextApp(props: {children: ReactNode; currentVault: [getBalance, props.currentVault, actionParams?.selectedOptionFrom?.decimals, isDepositing, limits?.maxDeposit] ); + const currentTimestamp = Math.floor(Date.now() / 1000); + const {data} = useReadContract({ + address: toAddress(VEYFI_ADDRESS), + abi: VEYFI_ABI, + functionName: 'locked', + args: [toAddress(address)], + query: { + enabled: !isZeroAddress(address) && props.currentVault.staking.source === 'VeYFI' + } + }); + + const {amount: veYFIBalance = 0n, end: lockEnds = 0n} = (data as {amount: bigint; end: bigint} | undefined) || {}; + /********************************************************************************************** ** The currentSolver is a memoized value that determines which solver should be used based on ** the current context. @@ -422,13 +438,15 @@ export function ActionFlowContextApp(props: {children: ReactNode; currentVault: return Solver.enum.OptimismBooster; } - // Only use GaugeStakingBooster if the user chose to stake automatically and the vault is staking with VeYFI + // Only use GaugeStakingBooster if the user chose to stake automatically, the vault is staking with VeYFI, and user has veYFI balance if ( props.currentVault.staking.available && props.currentVault.staking.source === 'VeYFI' && isAutoStakingEnabled && isDepositing && - isUnderlyingToken + isUnderlyingToken && + lockEnds > currentTimestamp && + veYFIBalance > 0n ) { return Solver.enum.GaugeStakingBooster; } @@ -508,6 +526,9 @@ export function ActionFlowContextApp(props: {children: ReactNode; currentVault: props.currentVault?.migration?.address, isAutoStakingEnabled, isDepositing, + lockEnds, + currentTimestamp, + veYFIBalance, isUsingPartnerContract, zapProvider ]); diff --git a/apps/vaults/utils/abi/veYFI.abi.ts b/apps/vaults/utils/abi/veYFI.abi.ts new file mode 100644 index 000000000..f583c92c6 --- /dev/null +++ b/apps/vaults/utils/abi/veYFI.abi.ts @@ -0,0 +1,260 @@ +export const VEYFI_ABI = [ + { + name: 'ModifyLock', + inputs: [ + {name: 'sender', type: 'address', indexed: true}, + {name: 'user', type: 'address', indexed: true}, + {name: 'amount', type: 'uint256', indexed: false}, + {name: 'locktime', type: 'uint256', indexed: false}, + {name: 'ts', type: 'uint256', indexed: false} + ], + anonymous: false, + type: 'event' + }, + { + name: 'Withdraw', + inputs: [ + {name: 'user', type: 'address', indexed: true}, + {name: 'amount', type: 'uint256', indexed: false}, + {name: 'ts', type: 'uint256', indexed: false} + ], + anonymous: false, + type: 'event' + }, + { + name: 'Penalty', + inputs: [ + {name: 'user', type: 'address', indexed: true}, + {name: 'amount', type: 'uint256', indexed: false}, + {name: 'ts', type: 'uint256', indexed: false} + ], + anonymous: false, + type: 'event' + }, + { + name: 'Supply', + inputs: [ + {name: 'old_supply', type: 'uint256', indexed: false}, + {name: 'new_supply', type: 'uint256', indexed: false}, + {name: 'ts', type: 'uint256', indexed: false} + ], + anonymous: false, + type: 'event' + }, + { + name: 'Initialized', + inputs: [ + {name: 'token', type: 'address', indexed: false}, + {name: 'reward_pool', type: 'address', indexed: false} + ], + anonymous: false, + type: 'event' + }, + { + stateMutability: 'nonpayable', + type: 'constructor', + inputs: [ + {name: 'token', type: 'address'}, + {name: 'reward_pool', type: 'address'} + ], + outputs: [] + }, + { + stateMutability: 'view', + type: 'function', + name: 'get_last_user_point', + inputs: [{name: 'addr', type: 'address'}], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + {name: 'bias', type: 'int128'}, + {name: 'slope', type: 'int128'}, + {name: 'ts', type: 'uint256'}, + {name: 'blk', type: 'uint256'} + ] + } + ] + }, + {stateMutability: 'nonpayable', type: 'function', name: 'checkpoint', inputs: [], outputs: []}, + { + stateMutability: 'nonpayable', + type: 'function', + name: 'modify_lock', + inputs: [ + {name: 'amount', type: 'uint256'}, + {name: 'unlock_time', type: 'uint256'} + ], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + {name: 'amount', type: 'uint256'}, + {name: 'end', type: 'uint256'} + ] + } + ] + }, + { + stateMutability: 'nonpayable', + type: 'function', + name: 'modify_lock', + inputs: [ + {name: 'amount', type: 'uint256'}, + {name: 'unlock_time', type: 'uint256'}, + {name: 'user', type: 'address'} + ], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + {name: 'amount', type: 'uint256'}, + {name: 'end', type: 'uint256'} + ] + } + ] + }, + { + stateMutability: 'nonpayable', + type: 'function', + name: 'withdraw', + inputs: [], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + {name: 'amount', type: 'uint256'}, + {name: 'penalty', type: 'uint256'} + ] + } + ] + }, + { + stateMutability: 'view', + type: 'function', + name: 'find_epoch_by_timestamp', + inputs: [ + {name: 'user', type: 'address'}, + {name: 'ts', type: 'uint256'} + ], + outputs: [{name: '', type: 'uint256'}] + }, + { + stateMutability: 'view', + type: 'function', + name: 'balanceOf', + inputs: [{name: 'user', type: 'address'}], + outputs: [{name: '', type: 'uint256'}] + }, + { + stateMutability: 'view', + type: 'function', + name: 'balanceOf', + inputs: [ + {name: 'user', type: 'address'}, + {name: 'ts', type: 'uint256'} + ], + outputs: [{name: '', type: 'uint256'}] + }, + { + stateMutability: 'view', + type: 'function', + name: 'getPriorVotes', + inputs: [ + {name: 'user', type: 'address'}, + {name: 'height', type: 'uint256'} + ], + outputs: [{name: '', type: 'uint256'}] + }, + { + stateMutability: 'view', + type: 'function', + name: 'totalSupply', + inputs: [], + outputs: [{name: '', type: 'uint256'}] + }, + { + stateMutability: 'view', + type: 'function', + name: 'totalSupply', + inputs: [{name: 'ts', type: 'uint256'}], + outputs: [{name: '', type: 'uint256'}] + }, + { + stateMutability: 'view', + type: 'function', + name: 'totalSupplyAt', + inputs: [{name: 'height', type: 'uint256'}], + outputs: [{name: '', type: 'uint256'}] + }, + {stateMutability: 'view', type: 'function', name: 'token', inputs: [], outputs: [{name: '', type: 'address'}]}, + { + stateMutability: 'view', + type: 'function', + name: 'reward_pool', + inputs: [], + outputs: [{name: '', type: 'address'}] + }, + {stateMutability: 'view', type: 'function', name: 'name', inputs: [], outputs: [{name: '', type: 'string'}]}, + {stateMutability: 'view', type: 'function', name: 'symbol', inputs: [], outputs: [{name: '', type: 'string'}]}, + {stateMutability: 'view', type: 'function', name: 'decimals', inputs: [], outputs: [{name: '', type: 'uint8'}]}, + {stateMutability: 'view', type: 'function', name: 'supply', inputs: [], outputs: [{name: '', type: 'uint256'}]}, + { + stateMutability: 'view', + type: 'function', + name: 'locked', + inputs: [{name: 'arg0', type: 'address'}], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + {name: 'amount', type: 'uint256'}, + {name: 'end', type: 'uint256'} + ] + } + ] + }, + { + stateMutability: 'view', + type: 'function', + name: 'epoch', + inputs: [{name: 'arg0', type: 'address'}], + outputs: [{name: '', type: 'uint256'}] + }, + { + stateMutability: 'view', + type: 'function', + name: 'point_history', + inputs: [ + {name: 'arg0', type: 'address'}, + {name: 'arg1', type: 'uint256'} + ], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + {name: 'bias', type: 'int128'}, + {name: 'slope', type: 'int128'}, + {name: 'ts', type: 'uint256'}, + {name: 'blk', type: 'uint256'} + ] + } + ] + }, + { + stateMutability: 'view', + type: 'function', + name: 'slope_changes', + inputs: [ + {name: 'arg0', type: 'address'}, + {name: 'arg1', type: 'uint256'} + ], + outputs: [{name: '', type: 'int128'}] + } +];