From 86d769a8d6e34b302115ad2e6908f76a3197574a Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 10:42:34 -0700 Subject: [PATCH 001/143] Initial gas data slice state --- .../synapse-interface/slices/gasDataSlice.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 packages/synapse-interface/slices/gasDataSlice.ts diff --git a/packages/synapse-interface/slices/gasDataSlice.ts b/packages/synapse-interface/slices/gasDataSlice.ts new file mode 100644 index 0000000000..10d3a2297d --- /dev/null +++ b/packages/synapse-interface/slices/gasDataSlice.ts @@ -0,0 +1,27 @@ +import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' + +export interface GasDataState { + gasData: { + gasPrice: bigint + maxFeePerGas: bigint + maxPriorityFeePerGas: bigint + formatted: { + gasPrice: string + maxFeePerGas: string + maxPriorityFeePerGas: string + } + } +} + +const initialState: GasDataState = { + gasData: { + gasPrice: null, + maxFeePerGas: null, + maxPriorityFeePerGas: null, + formatted: { + gasPrice: null, + maxFeePerGas: null, + maxPriorityFeePerGas: null, + }, + }, +} From 57866b3594ab76c138b893325ff1bd7ca820d41e Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 10:46:27 -0700 Subject: [PATCH 002/143] Async thunk fetchGasData --- .../synapse-interface/slices/gasDataSlice.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/synapse-interface/slices/gasDataSlice.ts b/packages/synapse-interface/slices/gasDataSlice.ts index 10d3a2297d..01ab468316 100644 --- a/packages/synapse-interface/slices/gasDataSlice.ts +++ b/packages/synapse-interface/slices/gasDataSlice.ts @@ -1,4 +1,5 @@ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' +import { fetchFeeData } from '@wagmi/core' export interface GasDataState { gasData: { @@ -13,6 +14,22 @@ export interface GasDataState { } } +const getFeeData = async (chainId: number) => { + const feeData = await fetchFeeData({ + chainId, + }) + + return feeData +} + +export const fetchGasData = createAsyncThunk( + 'gasData/fetchGasData', + async (chainId: number) => { + const gasData = await getFeeData(chainId) + return gasData + } +) + const initialState: GasDataState = { gasData: { gasPrice: null, From b2a2ec049a55557160586dff75dd2ed858a4763c Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 10:49:51 -0700 Subject: [PATCH 003/143] Add gas data reducers --- .../synapse-interface/slices/gasDataSlice.ts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/synapse-interface/slices/gasDataSlice.ts b/packages/synapse-interface/slices/gasDataSlice.ts index 01ab468316..afde31276a 100644 --- a/packages/synapse-interface/slices/gasDataSlice.ts +++ b/packages/synapse-interface/slices/gasDataSlice.ts @@ -12,9 +12,10 @@ export interface GasDataState { maxPriorityFeePerGas: string } } + isLoadingGasData: boolean } -const getFeeData = async (chainId: number) => { +const getGasData = async (chainId: number) => { const feeData = await fetchFeeData({ chainId, }) @@ -25,7 +26,7 @@ const getFeeData = async (chainId: number) => { export const fetchGasData = createAsyncThunk( 'gasData/fetchGasData', async (chainId: number) => { - const gasData = await getFeeData(chainId) + const gasData = await getGasData(chainId) return gasData } ) @@ -41,4 +42,27 @@ const initialState: GasDataState = { maxPriorityFeePerGas: null, }, }, + isLoadingGasData: true, } + +export const gasDataSlice = createSlice({ + name: 'gasData', + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(fetchGasData.pending, (state) => { + state.isLoadingGasData = true + }) + builder + .addCase(fetchGasData.fulfilled, (state, action) => { + state.isLoadingGasData = false + state.gasData = action.payload + }) + .addCase(fetchGasData.rejected, (state) => { + state.isLoadingGasData = false + console.error('Error fetching gas data') + }) + }, +}) + +export default gasDataSlice.reducer From 2eeb3ab5617d9fda6196abc26f491dd72ceb1f77 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:01:35 -0700 Subject: [PATCH 004/143] useFetchGasDataOnInterval added to Bridge Listener --- .../contexts/BackgroundListenerProvider.tsx | 2 ++ .../utils/hooks/useFetchGasDataOnInterval.ts | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts diff --git a/packages/synapse-interface/contexts/BackgroundListenerProvider.tsx b/packages/synapse-interface/contexts/BackgroundListenerProvider.tsx index 501484ef5b..181b806ba2 100644 --- a/packages/synapse-interface/contexts/BackgroundListenerProvider.tsx +++ b/packages/synapse-interface/contexts/BackgroundListenerProvider.tsx @@ -7,6 +7,7 @@ import { useRiskEvent } from '@/utils/hooks/useRiskEvent' import { useTransactionListener } from '@/utils/hooks/useTransactionListener' import { use_TransactionsListener } from '@/utils/hooks/use_TransactionsListener' import { useFetchPricesOnInterval } from '@/utils/hooks/useFetchPricesOnInterval' +import { useFetchGasDataOnInterval } from '@/utils/hooks/useFetchGasDataOnInterval' const BackgroundListenerContext = createContext(null) @@ -18,6 +19,7 @@ export const BackgroundListenerProvider = ({ children }) => { useBridgeListener() useRiskEvent() useFetchPricesOnInterval() + useFetchGasDataOnInterval() return ( diff --git a/packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts b/packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts new file mode 100644 index 0000000000..dc347d206e --- /dev/null +++ b/packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts @@ -0,0 +1,26 @@ +import { useEffect } from 'react' +import { useNetwork } from 'wagmi' + +import { useAppDispatch } from '@/store/hooks' +import { fetchGasData } from '@/slices/gasDataSlice' + +export const useFetchGasDataOnInterval = () => { + const dispatch = useAppDispatch() + const { chain } = useNetwork() + + const fetchData = (chainId: number) => { + dispatch(fetchGasData(chainId)) + } + + useEffect(() => { + // Fetch when chainId available + if (chain?.id) { + fetchData(chain?.id) + } + + // Fetch every 60 seconds + const interval = setInterval(fetchGasData, 60000) + + return () => clearInterval(interval) + }, [dispatch, chain?.id]) +} From c0db7cf77467b397a851af9b9be3403fe8d08769 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:19:26 -0700 Subject: [PATCH 005/143] Explicitly declare fetching gas data in gwei --- packages/synapse-interface/slices/gasDataSlice.ts | 1 + packages/synapse-interface/store/reducer.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/synapse-interface/slices/gasDataSlice.ts b/packages/synapse-interface/slices/gasDataSlice.ts index afde31276a..232e342921 100644 --- a/packages/synapse-interface/slices/gasDataSlice.ts +++ b/packages/synapse-interface/slices/gasDataSlice.ts @@ -18,6 +18,7 @@ export interface GasDataState { const getGasData = async (chainId: number) => { const feeData = await fetchFeeData({ chainId, + formatUnits: 'gwei', }) return feeData diff --git a/packages/synapse-interface/store/reducer.ts b/packages/synapse-interface/store/reducer.ts index 0545c62305..48698305bd 100644 --- a/packages/synapse-interface/store/reducer.ts +++ b/packages/synapse-interface/store/reducer.ts @@ -14,6 +14,7 @@ import poolDeposit from '@/slices/poolDepositSlice' import poolUserData from '@/slices/poolUserDataSlice' import poolWithdraw from '@/slices/poolWithdrawSlice' import priceData from '@/slices/priceDataSlice' +import gasData from '@/slices/gasDataSlice' import swapDisplay from '@/slices/swapDisplaySlice' import { api } from '@/slices/api/slice' import { RootActions } from '@/slices/application/actions' @@ -43,6 +44,7 @@ export const appReducer = combineReducers({ poolUserData, poolWithdraw, priceData, + gasData, swapDisplay, [api.reducerPath]: api.reducer, ...persistedReducers, From 365c0178513144ff760eec87ffca74f482dd31c9 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:10:23 -0700 Subject: [PATCH 006/143] Calculate max bridgeable amount --- .../StateManagedBridge/InputContainer.tsx | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index f81d75a6f3..0a12e94067 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react' +import { useAppSelector } from '@/store/hooks' import { useDispatch } from 'react-redux' import { useAccount, useNetwork } from 'wagmi' @@ -15,11 +16,17 @@ import { FromChainSelector } from './FromChainSelector' import { FromTokenSelector } from './FromTokenSelector' import { useBridgeState } from '@/slices/bridge/hooks' import { usePortfolioState } from '@/slices/portfolio/hooks' +import { zeroAddress } from 'viem' +import { formatGwei } from 'viem' export const inputRef = React.createRef() export const InputContainer = () => { const { fromChainId, fromToken, fromValue } = useBridgeState() + const { gasData } = useAppSelector((state) => state.gasData) + + const { gasPrice, maxFeePerGas } = gasData?.formatted + const [showValue, setShowValue] = useState('') const [hasMounted, setHasMounted] = useState(false) @@ -43,6 +50,17 @@ export const InputContainer = () => { (token) => token.tokenAddress === fromToken?.addresses[fromChainId] )?.balance + const estimatedGasCostInGwei = 200_000 * parseFloat(gasPrice) + const oneGwei = parseFloat(formatGwei(1n)) + const formattedEstimatedGasCost = estimatedGasCostInGwei + ? estimatedGasCostInGwei * oneGwei + : null + + const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress + + console.log('parsedBalance:', typeof parsedBalance) + console.log('formattedEstimatedGasCost:', typeof formattedEstimatedGasCost) + useEffect(() => { if (fromToken && fromToken?.decimals[fromChainId]) { setShowValue(fromValue) @@ -73,12 +91,36 @@ export const InputContainer = () => { } const onMaxBalance = useCallback(() => { - dispatch( - updateFromValue( - formatBigIntToString(balance, fromToken?.decimals[fromChainId]) + if (formattedEstimatedGasCost && isNativeToken) { + const maxBalance = Number(parsedBalance) - formattedEstimatedGasCost + + if (maxBalance < 0) { + updateFromValue( + formatBigIntToString(0n, fromToken?.decimals[fromChainId]) + ) + } else { + updateFromValue( + formatBigIntToString( + BigInt(maxBalance), + fromToken?.decimals[fromChainId] + ) + ) + } + } else { + dispatch( + updateFromValue( + formatBigIntToString(balance, fromToken?.decimals[fromChainId]) + ) ) - ) - }, [balance, fromChainId, fromToken]) + } + }, [ + parsedBalance, + balance, + fromChainId, + fromToken, + formattedEstimatedGasCost, + isNativeToken, + ]) const connectedStatus = useMemo(() => { if (hasMounted && !isConnected) { From c75c77f456a2cd88be7b9ffb875989683affd20c Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:33:15 -0700 Subject: [PATCH 007/143] On max balance factoring in gas cost --- .../StateManagedBridge/InputContainer.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 0a12e94067..e8e2ecc28f 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -95,16 +95,15 @@ export const InputContainer = () => { const maxBalance = Number(parsedBalance) - formattedEstimatedGasCost if (maxBalance < 0) { - updateFromValue( - formatBigIntToString(0n, fromToken?.decimals[fromChainId]) - ) - } else { - updateFromValue( - formatBigIntToString( - BigInt(maxBalance), - fromToken?.decimals[fromChainId] + console.log('max balance less than 0: ', maxBalance) + dispatch( + updateFromValue( + formatBigIntToString(0n, fromToken?.decimals[fromChainId]) ) ) + } else { + console.log('max balance greater than 0', maxBalance) + dispatch(updateFromValue(maxBalance.toString())) } } else { dispatch( From c16b27604ea553af081b185b95b8486168369f58 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:40:54 -0700 Subject: [PATCH 008/143] Add comment --- .../components/StateManagedBridge/InputContainer.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index e8e2ecc28f..8501e8aa6a 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -50,6 +50,11 @@ export const InputContainer = () => { (token) => token.tokenAddress === fromToken?.addresses[fromChainId] )?.balance + /** + * Gas static calculations + * Hardcoding gas limit to 200k for now + * TODO: update this to become dynamic with Bridge requests + */ const estimatedGasCostInGwei = 200_000 * parseFloat(gasPrice) const oneGwei = parseFloat(formatGwei(1n)) const formattedEstimatedGasCost = estimatedGasCostInGwei @@ -58,9 +63,6 @@ export const InputContainer = () => { const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress - console.log('parsedBalance:', typeof parsedBalance) - console.log('formattedEstimatedGasCost:', typeof formattedEstimatedGasCost) - useEffect(() => { if (fromToken && fromToken?.decimals[fromChainId]) { setShowValue(fromValue) From 0bf73d397c0a227b655f45ceba31f9027514e8df Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:24:39 -0700 Subject: [PATCH 009/143] Differentiate max balance vs max bridgeable balance --- .../components/StateManagedBridge/InputContainer.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 8501e8aa6a..2840092200 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -93,6 +93,14 @@ export const InputContainer = () => { } const onMaxBalance = useCallback(() => { + dispatch( + updateFromValue( + formatBigIntToString(balance, fromToken?.decimals[fromChainId]) + ) + ) + }, [balance, fromChainId, fromToken]) + + const onMaxBridgeableBalance = useCallback(() => { if (formattedEstimatedGasCost && isNativeToken) { const maxBalance = Number(parsedBalance) - formattedEstimatedGasCost @@ -201,7 +209,7 @@ export const InputContainer = () => {
)} From e821ef8a29eea1ba0dc29eabaed9049d04b9c77b Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:29:03 -0700 Subject: [PATCH 010/143] Add error toaster for when max balance less than bridge fee --- .../components/StateManagedBridge/InputContainer.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 2840092200..0d91bcb84d 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -1,8 +1,9 @@ +import toast from 'react-hot-toast' import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react' import { useAppSelector } from '@/store/hooks' import { useDispatch } from 'react-redux' +import { zeroAddress, formatGwei } from 'viem' import { useAccount, useNetwork } from 'wagmi' - import { initialState, updateFromValue } from '@/slices/bridge/reducer' import MiniMaxButton from '../buttons/MiniMaxButton' import { formatBigIntToString } from '@/utils/bigint/format' @@ -16,8 +17,6 @@ import { FromChainSelector } from './FromChainSelector' import { FromTokenSelector } from './FromTokenSelector' import { useBridgeState } from '@/slices/bridge/hooks' import { usePortfolioState } from '@/slices/portfolio/hooks' -import { zeroAddress } from 'viem' -import { formatGwei } from 'viem' export const inputRef = React.createRef() @@ -105,14 +104,17 @@ export const InputContainer = () => { const maxBalance = Number(parsedBalance) - formattedEstimatedGasCost if (maxBalance < 0) { - console.log('max balance less than 0: ', maxBalance) + toast.error(`Balance is less than estimated gas fee.`, { + id: 'not-enough-balance-popup', + duration: 5000, + }) + dispatch( updateFromValue( formatBigIntToString(0n, fromToken?.decimals[fromChainId]) ) ) } else { - console.log('max balance greater than 0', maxBalance) dispatch(updateFromValue(maxBalance.toString())) } } else { From 9f092397164f1a0b6e93ebe82d90215007883636 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:35:17 -0700 Subject: [PATCH 011/143] refactor; calculateGasFeeInGwei() --- .../StateManagedBridge/InputContainer.tsx | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 0d91bcb84d..f1a98c825a 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -18,6 +18,27 @@ import { FromTokenSelector } from './FromTokenSelector' import { useBridgeState } from '@/slices/bridge/hooks' import { usePortfolioState } from '@/slices/portfolio/hooks' +/** + * Calculates the estimated gas fee in Gwei. + * TODO: Hardcoding gas limit to 200k for now, update dynamically + * @param {string} gasPrice - The current gas price in Gwei as a string. + * @param {number} gasLimit - Function to format a value as Gwei. + * @returns {number|null} The formatted estimated gas cost, or null if the calculation is not possible. + */ +const calculateGasFeeInGwei = (gasPrice?: string, gasLimit = 200_000) => { + if (!gasPrice) return null + + const estimatedGasCostInGwei = gasLimit * parseFloat(gasPrice) + + const oneGwei = parseFloat(formatGwei(1n)) + + const formattedEstimatedGasCost = estimatedGasCostInGwei + ? estimatedGasCostInGwei * oneGwei + : null + + return formattedEstimatedGasCost +} + export const inputRef = React.createRef() export const InputContainer = () => { @@ -49,16 +70,7 @@ export const InputContainer = () => { (token) => token.tokenAddress === fromToken?.addresses[fromChainId] )?.balance - /** - * Gas static calculations - * Hardcoding gas limit to 200k for now - * TODO: update this to become dynamic with Bridge requests - */ - const estimatedGasCostInGwei = 200_000 * parseFloat(gasPrice) - const oneGwei = parseFloat(formatGwei(1n)) - const formattedEstimatedGasCost = estimatedGasCostInGwei - ? estimatedGasCostInGwei * oneGwei - : null + const estimatedGasCostInGwei = calculateGasFeeInGwei(gasPrice, 200_000) const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress @@ -100,8 +112,8 @@ export const InputContainer = () => { }, [balance, fromChainId, fromToken]) const onMaxBridgeableBalance = useCallback(() => { - if (formattedEstimatedGasCost && isNativeToken) { - const maxBalance = Number(parsedBalance) - formattedEstimatedGasCost + if (estimatedGasCostInGwei && isNativeToken) { + const maxBalance = Number(parsedBalance) - estimatedGasCostInGwei if (maxBalance < 0) { toast.error(`Balance is less than estimated gas fee.`, { @@ -129,7 +141,7 @@ export const InputContainer = () => { balance, fromChainId, fromToken, - formattedEstimatedGasCost, + estimatedGasCostInGwei, isNativeToken, ]) From 6d12c413097be9df9defa6014f219026af1f6db1 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:44:51 -0700 Subject: [PATCH 012/143] Move to util --- .../StateManagedBridge/InputContainer.tsx | 24 ++----------------- .../utils/calculateGasFeeInGwei.ts | 22 +++++++++++++++++ 2 files changed, 24 insertions(+), 22 deletions(-) create mode 100644 packages/synapse-interface/utils/calculateGasFeeInGwei.ts diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index f1a98c825a..509e9ba65a 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -2,7 +2,7 @@ import toast from 'react-hot-toast' import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react' import { useAppSelector } from '@/store/hooks' import { useDispatch } from 'react-redux' -import { zeroAddress, formatGwei } from 'viem' +import { zeroAddress } from 'viem' import { useAccount, useNetwork } from 'wagmi' import { initialState, updateFromValue } from '@/slices/bridge/reducer' import MiniMaxButton from '../buttons/MiniMaxButton' @@ -17,27 +17,7 @@ import { FromChainSelector } from './FromChainSelector' import { FromTokenSelector } from './FromTokenSelector' import { useBridgeState } from '@/slices/bridge/hooks' import { usePortfolioState } from '@/slices/portfolio/hooks' - -/** - * Calculates the estimated gas fee in Gwei. - * TODO: Hardcoding gas limit to 200k for now, update dynamically - * @param {string} gasPrice - The current gas price in Gwei as a string. - * @param {number} gasLimit - Function to format a value as Gwei. - * @returns {number|null} The formatted estimated gas cost, or null if the calculation is not possible. - */ -const calculateGasFeeInGwei = (gasPrice?: string, gasLimit = 200_000) => { - if (!gasPrice) return null - - const estimatedGasCostInGwei = gasLimit * parseFloat(gasPrice) - - const oneGwei = parseFloat(formatGwei(1n)) - - const formattedEstimatedGasCost = estimatedGasCostInGwei - ? estimatedGasCostInGwei * oneGwei - : null - - return formattedEstimatedGasCost -} +import { calculateGasFeeInGwei } from '../../utils/calculateGasFeeInGwei' export const inputRef = React.createRef() diff --git a/packages/synapse-interface/utils/calculateGasFeeInGwei.ts b/packages/synapse-interface/utils/calculateGasFeeInGwei.ts new file mode 100644 index 0000000000..1f769bdfb4 --- /dev/null +++ b/packages/synapse-interface/utils/calculateGasFeeInGwei.ts @@ -0,0 +1,22 @@ +import { formatGwei } from 'viem' + +/** + * Calculates the estimated gas fee in Gwei. + * TODO: Hardcoding gas limit to 200k for now, update dynamically + * @param {string} gasPrice - The current gas price in Gwei as a string. + * @param {number} gasLimit - Function to format a value as Gwei. + * @returns {number|null} The formatted estimated gas cost, or null if the calculation is not possible. + */ +export const calculateGasFeeInGwei = (gasPrice?: string, gasLimit = 200000) => { + if (!gasPrice) return null + + const estimatedGasCostInGwei = gasLimit * parseFloat(gasPrice) + + const oneGwei = parseFloat(formatGwei(1n)) + + const formattedEstimatedGasCost = estimatedGasCostInGwei + ? estimatedGasCostInGwei * oneGwei + : null + + return formattedEstimatedGasCost +} From 97581126a09b4b474da9e1bd48184d30889a3321 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:00:06 -0700 Subject: [PATCH 013/143] Fix lint error --- packages/synapse-interface/utils/calculateGasFeeInGwei.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/synapse-interface/utils/calculateGasFeeInGwei.ts b/packages/synapse-interface/utils/calculateGasFeeInGwei.ts index 1f769bdfb4..3a97d25d99 100644 --- a/packages/synapse-interface/utils/calculateGasFeeInGwei.ts +++ b/packages/synapse-interface/utils/calculateGasFeeInGwei.ts @@ -3,10 +3,12 @@ import { formatGwei } from 'viem' /** * Calculates the estimated gas fee in Gwei. * TODO: Hardcoding gas limit to 200k for now, update dynamically + * * @param {string} gasPrice - The current gas price in Gwei as a string. * @param {number} gasLimit - Function to format a value as Gwei. * @returns {number|null} The formatted estimated gas cost, or null if the calculation is not possible. */ + export const calculateGasFeeInGwei = (gasPrice?: string, gasLimit = 200000) => { if (!gasPrice) return null From 14968420c7189dd8b59d810f1a3533fe6b248561 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:33:17 -0700 Subject: [PATCH 014/143] Fetch gas when fromChainId on bridge card changes --- .../utils/hooks/useFetchGasDataOnInterval.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts b/packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts index dc347d206e..da8e72b362 100644 --- a/packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts +++ b/packages/synapse-interface/utils/hooks/useFetchGasDataOnInterval.ts @@ -1,12 +1,12 @@ import { useEffect } from 'react' -import { useNetwork } from 'wagmi' import { useAppDispatch } from '@/store/hooks' import { fetchGasData } from '@/slices/gasDataSlice' +import { useBridgeState } from '@/slices/bridge/hooks' export const useFetchGasDataOnInterval = () => { const dispatch = useAppDispatch() - const { chain } = useNetwork() + const { fromChainId } = useBridgeState() const fetchData = (chainId: number) => { dispatch(fetchGasData(chainId)) @@ -14,13 +14,13 @@ export const useFetchGasDataOnInterval = () => { useEffect(() => { // Fetch when chainId available - if (chain?.id) { - fetchData(chain?.id) + if (fromChainId) { + fetchData(fromChainId) } // Fetch every 60 seconds const interval = setInterval(fetchGasData, 60000) return () => clearInterval(interval) - }, [dispatch, chain?.id]) + }, [dispatch, fromChainId]) } From c01109fe94328247ee62441e48d3a7659b64c391 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:41:09 -0700 Subject: [PATCH 015/143] Use exact token balance when calculate max bridgeable amount --- .../StateManagedBridge/InputContainer.tsx | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 509e9ba65a..62e99aa34f 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -42,14 +42,19 @@ export const InputContainer = () => { const dispatch = useDispatch() - const parsedBalance = balances[fromChainId]?.find( - (token) => token.tokenAddress === fromToken?.addresses[fromChainId] - )?.parsedBalance - const balance = balances[fromChainId]?.find( (token) => token.tokenAddress === fromToken?.addresses[fromChainId] )?.balance + const shortenedParsedBalance = balances[fromChainId]?.find( + (token) => token.tokenAddress === fromToken?.addresses[fromChainId] + )?.parsedBalance + + const fullParsedBalance = formatBigIntToString( + balance, + fromToken?.decimals[fromChainId] + ) + const estimatedGasCostInGwei = calculateGasFeeInGwei(gasPrice, 200_000) const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress @@ -93,7 +98,10 @@ export const InputContainer = () => { const onMaxBridgeableBalance = useCallback(() => { if (estimatedGasCostInGwei && isNativeToken) { - const maxBalance = Number(parsedBalance) - estimatedGasCostInGwei + const maxBalance = Number(fullParsedBalance) - estimatedGasCostInGwei + + console.log('fullParsedBalance; ', fullParsedBalance) + console.log('estimatedGasCostInGwei:', estimatedGasCostInGwei) if (maxBalance < 0) { toast.error(`Balance is less than estimated gas fee.`, { @@ -117,7 +125,7 @@ export const InputContainer = () => { ) } }, [ - parsedBalance, + shortenedParsedBalance, balance, fromChainId, fromToken, @@ -189,7 +197,7 @@ export const InputContainer = () => { className="text-xs text-white transition-all duration-150 transform-gpu hover:text-opacity-70 hover:cursor-pointer" onClick={onMaxBalance} > - {parsedBalance ?? '0.0'} + {shortenedParsedBalance ?? '0.0'} {' '} available From eee9c509fdc0e7b25aa68e53caf772966ec9f860 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:25:25 -0700 Subject: [PATCH 016/143] Conditions for showing max button --- .../components/StateManagedBridge/InputContainer.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 62e99aa34f..62a62ad97d 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -1,5 +1,6 @@ import toast from 'react-hot-toast' import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react' +import { isNull } from 'lodash' import { useAppSelector } from '@/store/hooks' import { useDispatch } from 'react-redux' import { zeroAddress } from 'viem' @@ -55,10 +56,12 @@ export const InputContainer = () => { fromToken?.decimals[fromChainId] ) - const estimatedGasCostInGwei = calculateGasFeeInGwei(gasPrice, 200_000) + const estimatedGasCostInGwei = calculateGasFeeInGwei(maxFeePerGas, 200_000) const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress + console.log('estimatedGasCostInGwei: ', estimatedGasCostInGwei) + useEffect(() => { if (fromToken && fromToken?.decimals[fromChainId]) { setShowValue(fromValue) @@ -143,6 +146,13 @@ export const InputContainer = () => { } }, [chain, fromChainId, isConnected, hasMounted]) + const showMaxOption = () => { + if (!hasMounted || !isConnected) return false + if (!isNativeToken) return true + + if (isNativeToken && isNull(estimatedGasCostInGwei)) return false + } + return (
Date: Thu, 4 Apr 2024 12:52:52 -0700 Subject: [PATCH 017/143] showMaxOption to determine display --- .../components/StateManagedBridge/InputContainer.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 62a62ad97d..5169dc497c 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -148,11 +148,13 @@ export const InputContainer = () => { const showMaxOption = () => { if (!hasMounted || !isConnected) return false - if (!isNativeToken) return true - if (isNativeToken && isNull(estimatedGasCostInGwei)) return false + + return true } + console.log('showMaxOption(): ', showMaxOption()) + return (
{ style={{ display: 'table-cell', width: '100%' }} />
- {hasMounted && isConnected && ( + {showMaxOption() && (
- {hasMounted && isConnected && ( + {showMaxOption() && (
Date: Thu, 4 Apr 2024 13:10:16 -0700 Subject: [PATCH 018/143] Disable max button if gas fees more than gas balance --- .../StateManagedBridge/InputContainer.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 5169dc497c..1a1b1f19fd 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -60,6 +60,7 @@ export const InputContainer = () => { const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress + console.log('fullParsedBalance:', fullParsedBalance) console.log('estimatedGasCostInGwei: ', estimatedGasCostInGwei) useEffect(() => { @@ -146,6 +147,17 @@ export const InputContainer = () => { } }, [chain, fromChainId, isConnected, hasMounted]) + const isGasBalanceLessThanFees = () => { + if (isNativeToken && estimatedGasCostInGwei && fullParsedBalance) { + const gasBalance = fullParsedBalance + const gasFees = estimatedGasCostInGwei + + return gasFees > parseFloat(gasBalance) + } else { + return false + } + } + const showMaxOption = () => { if (!hasMounted || !isConnected) return false if (isNativeToken && isNull(estimatedGasCostInGwei)) return false @@ -154,7 +166,7 @@ export const InputContainer = () => { } console.log('showMaxOption(): ', showMaxOption()) - + console.log('isGasBalanceLessThanFees: ', isGasBalanceLessThanFees()) return (
{ {showMaxOption() && (
From f580a8046eee2c614fd133d3fc6374c872c7a0c8 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 4 Apr 2024 13:31:50 -0700 Subject: [PATCH 019/143] Clean jsx --- .../StateManagedBridge/InputContainer.tsx | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 1a1b1f19fd..fe5fc00bed 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -167,6 +167,7 @@ export const InputContainer = () => { console.log('showMaxOption(): ', showMaxOption()) console.log('isGasBalanceLessThanFees: ', isGasBalanceLessThanFees()) + return (
{
@@ -192,34 +190,31 @@ export const InputContainer = () => {
{showMaxOption() && (
- {showMaxOption() && ( + {hasMounted && isConnected && (
- {showMaxOption() && ( + {showMaxButton() && (
{
) } + +const AvailableBalance = ( + parsedBalance: number, + estimatedGasCost: number, + isGasToken: boolean, + onMaxAvailableBalance: () => void, + onMaxBridgeableBalance: () => void +) => { + if (isGasToken) { + const hasEnoughGas = parsedBalance - estimatedGasCost > 0 + + return ( + + ) + } else { + return ( + + ) + } +} From b4c91bf65418681cfe0cca01f3179e74d7b32604 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:37:52 -0700 Subject: [PATCH 021/143] Return raw and formatted gas cost in calculateGasCost --- .../StateManagedBridge/InputContainer.tsx | 32 ++++++++-------- .../utils/calculateGasCost.ts | 38 +++++++++++++++++++ .../utils/calculateGasFeeInGwei.ts | 24 ------------ 3 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 packages/synapse-interface/utils/calculateGasCost.ts delete mode 100644 packages/synapse-interface/utils/calculateGasFeeInGwei.ts diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index db4ab751ac..727c9e614a 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -18,15 +18,12 @@ import { FromChainSelector } from './FromChainSelector' import { FromTokenSelector } from './FromTokenSelector' import { useBridgeState } from '@/slices/bridge/hooks' import { usePortfolioState } from '@/slices/portfolio/hooks' -import { calculateGasFeeInGwei } from '../../utils/calculateGasFeeInGwei' +import { calculateGasFee } from '../../utils/calculateGasCost' export const inputRef = React.createRef() export const InputContainer = () => { const { fromChainId, fromToken, fromValue } = useBridgeState() - const { gasData } = useAppSelector((state) => state.gasData) - - const { gasPrice, maxFeePerGas } = gasData?.formatted const [showValue, setShowValue] = useState('') @@ -56,12 +53,18 @@ export const InputContainer = () => { fromToken?.decimals[fromChainId] ) - const estimatedGasCostInGwei = calculateGasFeeInGwei(maxFeePerGas, 200_000) + const { gasData } = useAppSelector((state) => state.gasData) + const { gasPrice, maxFeePerGas } = gasData?.formatted + + const { rawGasCost, formattedGasCost } = calculateGasFee( + maxFeePerGas, + 200_000 + ) const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress console.log('fullParsedBalance:', fullParsedBalance) - console.log('estimatedGasCostInGwei: ', estimatedGasCostInGwei) + console.log('formattedGasCost: ', formattedGasCost) useEffect(() => { if (fromToken && fromToken?.decimals[fromChainId]) { @@ -100,12 +103,11 @@ export const InputContainer = () => { ) }, [balance, fromChainId, fromToken]) - const onMaxBridgeableBalance = useCallback(() => { - if (estimatedGasCostInGwei && isNativeToken) { - const maxBalance = Number(fullParsedBalance) - estimatedGasCostInGwei + const calculateMaxBridgeableGas = (parsedGasBalance) => {} - console.log('fullParsedBalance; ', fullParsedBalance) - console.log('estimatedGasCostInGwei:', estimatedGasCostInGwei) + const onMaxBridgeableBalance = useCallback(() => { + if (formattedGasCost && isNativeToken) { + const maxBalance = Number(fullParsedBalance) - formattedGasCost if (maxBalance < 0) { toast.error(`Balance is less than estimated gas fee.`, { @@ -133,7 +135,7 @@ export const InputContainer = () => { balance, fromChainId, fromToken, - estimatedGasCostInGwei, + formattedGasCost, isNativeToken, ]) @@ -148,9 +150,9 @@ export const InputContainer = () => { }, [chain, fromChainId, isConnected, hasMounted]) const isGasBalanceLessThanFees = () => { - if (isNativeToken && estimatedGasCostInGwei && fullParsedBalance) { + if (isNativeToken && formattedGasCost && fullParsedBalance) { const gasBalance = fullParsedBalance - const gasFees = estimatedGasCostInGwei + const gasFees = formattedGasCost return gasFees > parseFloat(gasBalance) } else { @@ -160,7 +162,7 @@ export const InputContainer = () => { const showMaxButton = () => { if (!hasMounted || !isConnected) return false - if (isNativeToken && isNull(estimatedGasCostInGwei)) return false + if (isNativeToken && isNull(formattedGasCost)) return false return true } diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts new file mode 100644 index 0000000000..673ece43b1 --- /dev/null +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -0,0 +1,38 @@ +import { formatGwei } from 'viem' + +/** + * Calculates the estimated gas cost for a transaction. + * TODO: Hardcoding gas limit to 200k for now, update dynamically + * + * @param {string} gasPrice - The current network gas price in Gwei + * @param {number} gasLimit - Selected gasLimit to execute Transaction + * @returns {number, number} returns gas cost in gwei and parsed + */ + +export const calculateGasCost = ( + gasPrice?: string, + gasLimit = 200000 +): { + rawGasCost: number + formattedGasCost: number +} => { + if (!gasPrice) { + return { + rawGasCost: null, + formattedGasCost: null, + } + } + + const estimatedGasCostInGwei = gasLimit * parseFloat(gasPrice) + + const oneGwei = parseFloat(formatGwei(1n)) + + const formattedEstimatedGasCost = estimatedGasCostInGwei + ? estimatedGasCostInGwei * oneGwei + : null + + return { + rawGasCost: estimatedGasCostInGwei, + formattedGasCost: formattedEstimatedGasCost, + } +} diff --git a/packages/synapse-interface/utils/calculateGasFeeInGwei.ts b/packages/synapse-interface/utils/calculateGasFeeInGwei.ts deleted file mode 100644 index 3a97d25d99..0000000000 --- a/packages/synapse-interface/utils/calculateGasFeeInGwei.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { formatGwei } from 'viem' - -/** - * Calculates the estimated gas fee in Gwei. - * TODO: Hardcoding gas limit to 200k for now, update dynamically - * - * @param {string} gasPrice - The current gas price in Gwei as a string. - * @param {number} gasLimit - Function to format a value as Gwei. - * @returns {number|null} The formatted estimated gas cost, or null if the calculation is not possible. - */ - -export const calculateGasFeeInGwei = (gasPrice?: string, gasLimit = 200000) => { - if (!gasPrice) return null - - const estimatedGasCostInGwei = gasLimit * parseFloat(gasPrice) - - const oneGwei = parseFloat(formatGwei(1n)) - - const formattedEstimatedGasCost = estimatedGasCostInGwei - ? estimatedGasCostInGwei * oneGwei - : null - - return formattedEstimatedGasCost -} From 85c4a7fd53877025024e5e53efce121a95f38f13 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:38:10 -0700 Subject: [PATCH 022/143] Update comments --- packages/synapse-interface/utils/calculateGasCost.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts index 673ece43b1..29fb20bb55 100644 --- a/packages/synapse-interface/utils/calculateGasCost.ts +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -2,11 +2,11 @@ import { formatGwei } from 'viem' /** * Calculates the estimated gas cost for a transaction. + * * TODO: Hardcoding gas limit to 200k for now, update dynamically * * @param {string} gasPrice - The current network gas price in Gwei * @param {number} gasLimit - Selected gasLimit to execute Transaction - * @returns {number, number} returns gas cost in gwei and parsed */ export const calculateGasCost = ( From cd7ae73aa4fdcb7f24296eef2c0c803a9788683d Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:38:36 -0700 Subject: [PATCH 023/143] Fix imports based on name cange --- .../components/StateManagedBridge/InputContainer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 727c9e614a..b414d10e75 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -18,7 +18,7 @@ import { FromChainSelector } from './FromChainSelector' import { FromTokenSelector } from './FromTokenSelector' import { useBridgeState } from '@/slices/bridge/hooks' import { usePortfolioState } from '@/slices/portfolio/hooks' -import { calculateGasFee } from '../../utils/calculateGasCost' +import { calculateGasCost } from '../../utils/calculateGasCost' export const inputRef = React.createRef() @@ -56,7 +56,7 @@ export const InputContainer = () => { const { gasData } = useAppSelector((state) => state.gasData) const { gasPrice, maxFeePerGas } = gasData?.formatted - const { rawGasCost, formattedGasCost } = calculateGasFee( + const { rawGasCost, formattedGasCost } = calculateGasCost( maxFeePerGas, 200_000 ) From a10966226d189dd5f37379128b41810ae107ff8c Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:40:04 -0700 Subject: [PATCH 024/143] Use parsed --- .../StateManagedBridge/InputContainer.tsx | 21 ++++++++----------- .../utils/calculateGasCost.ts | 6 +++--- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index b414d10e75..fb0dfc7bf6 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -56,15 +56,12 @@ export const InputContainer = () => { const { gasData } = useAppSelector((state) => state.gasData) const { gasPrice, maxFeePerGas } = gasData?.formatted - const { rawGasCost, formattedGasCost } = calculateGasCost( - maxFeePerGas, - 200_000 - ) + const { rawGasCost, parsedGasCost } = calculateGasCost(maxFeePerGas, 200_000) const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress console.log('fullParsedBalance:', fullParsedBalance) - console.log('formattedGasCost: ', formattedGasCost) + console.log('formattedGasCost: ', parsedGasCost) useEffect(() => { if (fromToken && fromToken?.decimals[fromChainId]) { @@ -103,11 +100,11 @@ export const InputContainer = () => { ) }, [balance, fromChainId, fromToken]) - const calculateMaxBridgeableGas = (parsedGasBalance) => {} + const calculateMaxBridgeableGas = (formattedGasCost) => {} const onMaxBridgeableBalance = useCallback(() => { - if (formattedGasCost && isNativeToken) { - const maxBalance = Number(fullParsedBalance) - formattedGasCost + if (parsedGasCost && isNativeToken) { + const maxBalance = Number(fullParsedBalance) - parsedGasCost if (maxBalance < 0) { toast.error(`Balance is less than estimated gas fee.`, { @@ -135,7 +132,7 @@ export const InputContainer = () => { balance, fromChainId, fromToken, - formattedGasCost, + parsedGasCost, isNativeToken, ]) @@ -150,9 +147,9 @@ export const InputContainer = () => { }, [chain, fromChainId, isConnected, hasMounted]) const isGasBalanceLessThanFees = () => { - if (isNativeToken && formattedGasCost && fullParsedBalance) { + if (isNativeToken && parsedGasCost && fullParsedBalance) { const gasBalance = fullParsedBalance - const gasFees = formattedGasCost + const gasFees = parsedGasCost return gasFees > parseFloat(gasBalance) } else { @@ -162,7 +159,7 @@ export const InputContainer = () => { const showMaxButton = () => { if (!hasMounted || !isConnected) return false - if (isNativeToken && isNull(formattedGasCost)) return false + if (isNativeToken && isNull(parsedGasCost)) return false return true } diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts index 29fb20bb55..ce81e09acd 100644 --- a/packages/synapse-interface/utils/calculateGasCost.ts +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -14,12 +14,12 @@ export const calculateGasCost = ( gasLimit = 200000 ): { rawGasCost: number - formattedGasCost: number + parsedGasCost: number } => { if (!gasPrice) { return { rawGasCost: null, - formattedGasCost: null, + parsedGasCost: null, } } @@ -33,6 +33,6 @@ export const calculateGasCost = ( return { rawGasCost: estimatedGasCostInGwei, - formattedGasCost: formattedEstimatedGasCost, + parsedGasCost: formattedEstimatedGasCost, } } From e9266badaf607f20acc2704bf6f0381cc319c5d3 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:43:21 -0700 Subject: [PATCH 025/143] calculateMaxBridgeableGas --- .../StateManagedBridge/InputContainer.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index fb0dfc7bf6..281d77ac61 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -100,13 +100,22 @@ export const InputContainer = () => { ) }, [balance, fromChainId, fromToken]) - const calculateMaxBridgeableGas = (formattedGasCost) => {} + const calculateMaxBridgeableGas = ( + parsedGasBalance: number, + parsedGasCost: number + ) => { + const maxBridgeable = parsedGasBalance - parsedGasCost + return maxBridgeable + } const onMaxBridgeableBalance = useCallback(() => { if (parsedGasCost && isNativeToken) { - const maxBalance = Number(fullParsedBalance) - parsedGasCost + const maxBridgeable = calculateMaxBridgeableGas( + parseFloat(fullParsedBalance), + parsedGasCost + ) - if (maxBalance < 0) { + if (maxBridgeable < 0) { toast.error(`Balance is less than estimated gas fee.`, { id: 'not-enough-balance-popup', duration: 5000, @@ -118,7 +127,7 @@ export const InputContainer = () => { ) ) } else { - dispatch(updateFromValue(maxBalance.toString())) + dispatch(updateFromValue(maxBridgeable.toString())) } } else { dispatch( From 79d540cbe1aa67c6e00ebdfae01b191f68b559c7 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:47:25 -0700 Subject: [PATCH 026/143] Clean --- .../StateManagedBridge/InputContainer.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 281d77ac61..5b64d4a315 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -60,9 +60,6 @@ export const InputContainer = () => { const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress - console.log('fullParsedBalance:', fullParsedBalance) - console.log('formattedGasCost: ', parsedGasCost) - useEffect(() => { if (fromToken && fromToken?.decimals[fromChainId]) { setShowValue(fromValue) @@ -157,10 +154,7 @@ export const InputContainer = () => { const isGasBalanceLessThanFees = () => { if (isNativeToken && parsedGasCost && fullParsedBalance) { - const gasBalance = fullParsedBalance - const gasFees = parsedGasCost - - return gasFees > parseFloat(gasBalance) + return parsedGasCost > parseFloat(fullParsedBalance) } else { return false } @@ -172,8 +166,10 @@ export const InputContainer = () => { return true } - console.log('showMaxOption(): ', showMaxButton()) - console.log('isGasBalanceLessThanFees: ', isGasBalanceLessThanFees()) + // console.log('fullParsedBalance:', fullParsedBalance) + // console.log('formattedGasCost: ', parsedGasCost) + // console.log('showMaxOption(): ', showMaxButton()) + // console.log('isGasBalanceLessThanFees: ', isGasBalanceLessThanFees()) return (
Date: Fri, 5 Apr 2024 11:59:18 -0700 Subject: [PATCH 027/143] refactor: clean InputContainer --- .../StateManagedBridge/InputContainer.tsx | 85 +++++++++---------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 5b64d4a315..30edfef705 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -1,8 +1,7 @@ import toast from 'react-hot-toast' import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react' import { isNull } from 'lodash' -import { useAppSelector } from '@/store/hooks' -import { useDispatch } from 'react-redux' +import { useAppSelector, useAppDispatch } from '@/store/hooks' import { zeroAddress } from 'viem' import { useAccount, useNetwork } from 'wagmi' import { initialState, updateFromValue } from '@/slices/bridge/reducer' @@ -23,43 +22,32 @@ import { calculateGasCost } from '../../utils/calculateGasCost' export const inputRef = React.createRef() export const InputContainer = () => { - const { fromChainId, fromToken, fromValue } = useBridgeState() - + const dispatch = useAppDispatch() const [showValue, setShowValue] = useState('') - const [hasMounted, setHasMounted] = useState(false) - + const { chain } = useNetwork() + const { isConnected } = useAccount() + const { fromChainId, fromToken, fromValue } = useBridgeState() const { balances } = usePortfolioState() useEffect(() => { setHasMounted(true) }, []) - const { isConnected } = useAccount() - const { chain } = useNetwork() + const isGasToken = fromToken?.addresses[fromChainId] === zeroAddress - const dispatch = useDispatch() - - const balance = balances[fromChainId]?.find( + const selectedFromToken = balances[fromChainId]?.find( (token) => token.tokenAddress === fromToken?.addresses[fromChainId] - )?.balance + ) - const shortenedParsedBalance = balances[fromChainId]?.find( - (token) => token.tokenAddress === fromToken?.addresses[fromChainId] - )?.parsedBalance + const { balance: rawBalance, parsedBalance: trimmedParsedBalance } = + selectedFromToken - const fullParsedBalance = formatBigIntToString( - balance, + const parsedBalance = formatBigIntToString( + rawBalance, fromToken?.decimals[fromChainId] ) - const { gasData } = useAppSelector((state) => state.gasData) - const { gasPrice, maxFeePerGas } = gasData?.formatted - - const { rawGasCost, parsedGasCost } = calculateGasCost(maxFeePerGas, 200_000) - - const isNativeToken = fromToken?.addresses[fromChainId] === zeroAddress - useEffect(() => { if (fromToken && fromToken?.decimals[fromChainId]) { setShowValue(fromValue) @@ -92,23 +80,35 @@ export const InputContainer = () => { const onMaxBalance = useCallback(() => { dispatch( updateFromValue( - formatBigIntToString(balance, fromToken?.decimals[fromChainId]) + formatBigIntToString(rawBalance, fromToken?.decimals[fromChainId]) ) ) - }, [balance, fromChainId, fromToken]) + }, [rawBalance, fromChainId, fromToken]) + + const { gasData } = useAppSelector((state) => state.gasData) + const { gasPrice, maxFeePerGas } = gasData?.formatted + const { rawGasCost, parsedGasCost } = calculateGasCost(maxFeePerGas, 200_000) + + const isGasBalanceLessThanFees = (): boolean => { + if (isGasToken && parsedGasCost && parsedBalance) { + return parsedGasCost > parseFloat(parsedBalance) + } else { + return false + } + } const calculateMaxBridgeableGas = ( parsedGasBalance: number, parsedGasCost: number - ) => { + ): number => { const maxBridgeable = parsedGasBalance - parsedGasCost return maxBridgeable } const onMaxBridgeableBalance = useCallback(() => { - if (parsedGasCost && isNativeToken) { + if (isGasToken && parsedGasCost) { const maxBridgeable = calculateMaxBridgeableGas( - parseFloat(fullParsedBalance), + parseFloat(parsedBalance), parsedGasCost ) @@ -117,7 +117,6 @@ export const InputContainer = () => { id: 'not-enough-balance-popup', duration: 5000, }) - dispatch( updateFromValue( formatBigIntToString(0n, fromToken?.decimals[fromChainId]) @@ -129,17 +128,17 @@ export const InputContainer = () => { } else { dispatch( updateFromValue( - formatBigIntToString(balance, fromToken?.decimals[fromChainId]) + formatBigIntToString(rawBalance, fromToken?.decimals[fromChainId]) ) ) } }, [ - shortenedParsedBalance, - balance, fromChainId, fromToken, + isGasToken, parsedGasCost, - isNativeToken, + rawBalance, + trimmedParsedBalance, ]) const connectedStatus = useMemo(() => { @@ -152,21 +151,13 @@ export const InputContainer = () => { } }, [chain, fromChainId, isConnected, hasMounted]) - const isGasBalanceLessThanFees = () => { - if (isNativeToken && parsedGasCost && fullParsedBalance) { - return parsedGasCost > parseFloat(fullParsedBalance) - } else { - return false - } - } - - const showMaxButton = () => { + const showMaxButton = (): boolean => { if (!hasMounted || !isConnected) return false - if (isNativeToken && isNull(parsedGasCost)) return false + if (isGasToken && isNull(parsedGasCost)) return false return true } - // console.log('fullParsedBalance:', fullParsedBalance) + // console.log('parsedBalance:', parsedBalance) // console.log('formattedGasCost: ', parsedGasCost) // console.log('showMaxOption(): ', showMaxButton()) // console.log('isGasBalanceLessThanFees: ', isGasBalanceLessThanFees()) @@ -219,7 +210,7 @@ export const InputContainer = () => { hover:text-opacity-70 hover:cursor-pointer `} > - {shortenedParsedBalance ?? '0.0'} + {trimmedParsedBalance ?? '0.0'} {' '} available @@ -233,7 +224,7 @@ export const InputContainer = () => {
Date: Fri, 5 Apr 2024 12:02:07 -0700 Subject: [PATCH 028/143] Replace onMaxBalance() with onMaxBridgeableBalance()` --- .../components/StateManagedBridge/InputContainer.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 30edfef705..d6c067349a 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -77,14 +77,6 @@ export const InputContainer = () => { } } - const onMaxBalance = useCallback(() => { - dispatch( - updateFromValue( - formatBigIntToString(rawBalance, fromToken?.decimals[fromChainId]) - ) - ) - }, [rawBalance, fromChainId, fromToken]) - const { gasData } = useAppSelector((state) => state.gasData) const { gasPrice, maxFeePerGas } = gasData?.formatted const { rawGasCost, parsedGasCost } = calculateGasCost(maxFeePerGas, 200_000) @@ -204,7 +196,7 @@ export const InputContainer = () => { {hasMounted && isConnected && (
From 8d9c491ff2203e3237428770678cb3ad9e2bf53c Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Mon, 8 Apr 2024 10:57:50 -0700 Subject: [PATCH 033/143] Update avail balance text and color when gas cost greater than balance --- .../components/StateManagedBridge/InputContainer.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index d8a9a48f9d..09de2f22d1 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -217,10 +217,15 @@ export const InputContainer = () => { htmlFor="inputRow" className={` text-xs text-secondaryTextColor transition-all duration-150 transform-gpu + ${ + isGasToken && + isGasBalanceLessThanCost() && + 'text-yellow-500' + } `} > {parsedGasCost.toFixed(4)} - reserved for gas + estimated gas cost ) : (
{hasMounted && isConnected && - (showGasReserved() ? ( + (isGasToken && showGasReserved() && isGasInputLessThanCost() ? (
) } - -const AvailableBalance = ( - parsedBalance: number, - estimatedGasCost: number, - isGasToken: boolean, - onMaxAvailableBalance: () => void, - onMaxBridgeableBalance: () => void -) => { - if (isGasToken) { - const hasEnoughGas = parsedBalance - estimatedGasCost > 0 - - return ( - - ) - } else { - return ( - - ) - } -} From 342761607f05de6245672899415319f72df7e689 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Mon, 8 Apr 2024 15:58:57 -0700 Subject: [PATCH 039/143] Add hover tooltip for warning gas states --- .../StateManagedBridge/InputContainer.tsx | 93 +++++++++++++++++-- 1 file changed, 83 insertions(+), 10 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 87e5128b90..85b07d75a4 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -231,10 +231,25 @@ export const InputContainer = () => { isGasInputMoreThanBridgeableMax()) && 'text-yellow-500' } - `} + `} > - {parsedGasCost.toFixed(4)} - estimated gas cost + + Gas fees may exceed your available balance +
+ } + > + {parsedGasCost.toFixed(4)} + + {' '} + estimated gas cost + + ) : (
+ } + > + {isTraceBalance() + ? '< 0.0001' + : trimmedParsedBalance ?? '0.0'} + + {' '} + available + + ))}
@@ -275,3 +302,49 @@ export const InputContainer = () => {
) } + +// TODO: Replace with HoverTooltip in Portfolio once other branch is merged in +export const HoverTooltip = ({ children, hoverContent, active }) => { + const [showTooltip, setShowTooltip] = useState(false) + + const activateTooltip = () => setShowTooltip(true) + const hideTooltip = () => setShowTooltip(false) + + if (!active) { + return
{children}
+ } else { + return ( +
+ {children} + {hoverContent} +
+ ) + } +} + +const Tooltip = ({ + isHovered, + children, +}: { + isHovered: boolean + children: React.ReactNode +}) => { + if (isHovered) { + return ( +
+ {children} +
+ ) + } +} From 44edc571b3e470f8b6c610eb3d1e0c03305f2983 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:06:02 -0700 Subject: [PATCH 040/143] Use tooltip to describe gas status --- .../StateManagedBridge/InputContainer.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 85b07d75a4..6dfbfdce23 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -239,15 +239,21 @@ export const InputContainer = () => { isGasInputMoreThanBridgeableMax() } hoverContent={ -
- Gas fees may exceed your available balance -
+ isGasInputMoreThanBridgeableMax() ? ( +
+ Gas fees may exceed input +
+ ) : ( +
+ Gas fees may exceed your available balance +
+ ) } > {parsedGasCost.toFixed(4)} {' '} - estimated gas cost + estimated gas fee From 3052e579b2385d4b65943a55d47ad00386d374a2 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:45:46 -0700 Subject: [PATCH 041/143] Update tooltip text --- .../components/StateManagedBridge/InputContainer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 6dfbfdce23..2a287d6d4c 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -241,7 +241,7 @@ export const InputContainer = () => { hoverContent={ isGasInputMoreThanBridgeableMax() ? (
- Gas fees may exceed input + Requested bridge amount may not cover gas fees
) : (
From 86a3cfb24f0087b36c8b49b6d5d5c3d55caeb781 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:28:56 -0700 Subject: [PATCH 042/143] Add buffer to calculate gas cost, use 1.5x --- .../StateManagedBridge/InputContainer.tsx | 18 ++++++++++-------- .../utils/calculateGasCost.ts | 5 ++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 2a287d6d4c..7a48db3573 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -35,7 +35,7 @@ export const InputContainer = () => { const { gasData } = useAppSelector((state) => state.gasData) const { gasPrice, maxFeePerGas } = gasData?.formatted - const { rawGasCost, parsedGasCost } = calculateGasCost(maxFeePerGas, 200_000) + const { rawGasCost, parsedGasCost } = calculateGasCost(gasPrice, 200_000) const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress @@ -115,6 +115,11 @@ export const InputContainer = () => { ? calculateMaxBridgeableGas(parseFloat(parsedBalance), parsedGasCost) : null + console.log('rawGasCost:', rawGasCost) + console.log('parsedGasCost: ', parsedGasCost) + console.log('parsedGasBalance:', parseFloat(parsedBalance)) + console.log('maxBridgeableGas: ', maxBridgeableGas) + const onMaxBridgeableBalance = useCallback(() => { if (maxBridgeableGas) { if (maxBridgeableGas < 0) { @@ -234,7 +239,7 @@ export const InputContainer = () => { `} > { `} > Gas fees may exceed your available balance @@ -310,13 +312,13 @@ export const InputContainer = () => { } // TODO: Replace with HoverTooltip in Portfolio once other branch is merged in -export const HoverTooltip = ({ children, hoverContent, active }) => { +export const HoverTooltip = ({ children, hoverContent, isActive }) => { const [showTooltip, setShowTooltip] = useState(false) const activateTooltip = () => setShowTooltip(true) const hideTooltip = () => setShowTooltip(false) - if (!active) { + if (!isActive) { return
{children}
} else { return ( diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts index ce81e09acd..f670706296 100644 --- a/packages/synapse-interface/utils/calculateGasCost.ts +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -23,7 +23,10 @@ export const calculateGasCost = ( } } - const estimatedGasCostInGwei = gasLimit * parseFloat(gasPrice) + const upperLimitBuffer = 1.5 + + const estimatedGasCostInGwei = + gasLimit * parseFloat(gasPrice) * upperLimitBuffer const oneGwei = parseFloat(formatGwei(1n)) From b0e5e529409cb8ee42f72900d98fe60814a9c934 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:11:54 -0700 Subject: [PATCH 043/143] AvailableBalance component to replace label in AmountInput --- .../StateManagedBridge/InputContainer.tsx | 73 ++++++++++++++++--- .../components/ui/AmountInput.tsx | 6 +- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 072d059a33..7c95326e12 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -32,6 +32,7 @@ import { BridgeSectionContainer } from '@/components/ui/BridgeSectionContainer' import { BridgeAmountContainer } from '@/components/ui/BridgeAmountContainer' import { useFromTokenListArray } from './hooks/useFromTokenListArray' import MiniMaxButton from '../buttons/MiniMaxButton' +import { joinClassNames } from '@/utils/joinClassNames' export const inputRef = React.createRef() @@ -202,15 +203,24 @@ export const InputContainer = () => {
- +
+ + +
{hasMounted && isConnected && ( { ) } +const AvailableBalance = ({ + balance, + parsedBalance, + onMaxBalance, + hasMounted, + isConnected, + isGasToken = false, + disabled = false, +}: { + balance?: bigint + parsedBalance?: string + onMaxBalance?: () => void + hasMounted: boolean + isConnected: boolean + isGasToken?: boolean + disabled?: boolean +}) => { + const labelClassName = joinClassNames({ + space: 'block', + textColor: 'text-xxs md:text-xs', + animation: 'transition-all duration-150 transform-gpu', + hover: 'hover:opacity-70 cursor-pointer', + }) + + const isTraceBalance = (): boolean => { + if (!balance || !parsedBalance) return false + if (balance && hasOnlyZeroes(parsedBalance)) return true + return false + } + + if (hasMounted && isConnected && !disabled) { + return ( + + ) + } + return null +} + // TODO: Replace with HoverTooltip in Portfolio once other branch is merged in export const HoverTooltip = ({ children, hoverContent, isActive }) => { const [showTooltip, setShowTooltip] = useState(false) diff --git a/packages/synapse-interface/components/ui/AmountInput.tsx b/packages/synapse-interface/components/ui/AmountInput.tsx index 441f8b0d9d..03c6be6654 100644 --- a/packages/synapse-interface/components/ui/AmountInput.tsx +++ b/packages/synapse-interface/components/ui/AmountInput.tsx @@ -1,6 +1,7 @@ import React from 'react' import LoadingDots from './tailwind/LoadingDots' import { joinClassNames } from '@/utils/joinClassNames' +import { HoverTooltip } from '../StateManagedBridge/InputContainer' interface AmountInputTypes { inputRef?: React.RefObject @@ -13,6 +14,7 @@ interface AmountInputTypes { parsedBalance?: string onMaxBalance?: () => void } + export function AmountInput({ inputRef, disabled = false, @@ -59,7 +61,7 @@ export function AmountInput({ maxLength={79} /> )} - {hasMounted && isConnected && !disabled && ( + {/* {hasMounted && isConnected && !disabled && ( - )} + )} */}
) } From 06e10441b84bb409f6c2790d45f366c48f929ea0 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:25:41 -0700 Subject: [PATCH 044/143] Display trace balances in AvailableBalance --- .../StateManagedBridge/InputContainer.tsx | 22 ++++++++++++++----- .../utils/calculateGasCost.ts | 8 +++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 7c95326e12..66000626f8 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -124,7 +124,10 @@ export const InputContainer = () => { const maxBridgeableGas: number | null = isGasToken && parsedGasCost - ? calculateMaxBridgeableGas(parseFloat(parsedBalance), parsedGasCost) + ? calculateMaxBridgeableGas( + parseFloat(parsedBalance), + parseFloat(parsedGasCost) + ) : null console.log('rawGasCost:', rawGasCost) @@ -175,7 +178,10 @@ export const InputContainer = () => { const isGasInputMoreThanBridgeableMax = (): boolean => { if (isGasToken && parsedGasCost && fromValue && parsedBalance) { - return parseFloat(fromValue) > parseFloat(parsedBalance) - parsedGasCost + return ( + parseFloat(fromValue) > + parseFloat(parsedBalance) - parseFloat(parsedGasCost) + ) } else { return false } @@ -183,7 +189,7 @@ export const InputContainer = () => { const isGasBalanceLessThanCost = (): boolean => { if (isGasToken && parsedGasCost && parsedBalance) { - return parsedGasCost > parseFloat(parsedBalance) + return parseFloat(parsedGasCost) > parseFloat(parsedBalance) } else { return false } @@ -214,8 +220,10 @@ export const InputContainer = () => { onMaxBalance={onMaxBalance} /> { } const AvailableBalance = ({ + fromValue, balance, parsedBalance, + isGasToken = false, + parsedGasCost, onMaxBalance, hasMounted, isConnected, - isGasToken = false, disabled = false, }: { + fromValue: string balance?: bigint parsedBalance?: string + isGasToken?: boolean + parsedGasCost?: string onMaxBalance?: () => void hasMounted: boolean isConnected: boolean - isGasToken?: boolean disabled?: boolean }) => { const labelClassName = joinClassNames({ diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts index f670706296..c4c2c41dbc 100644 --- a/packages/synapse-interface/utils/calculateGasCost.ts +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -13,8 +13,8 @@ export const calculateGasCost = ( gasPrice?: string, gasLimit = 200000 ): { - rawGasCost: number - parsedGasCost: number + rawGasCost: string + parsedGasCost: string } => { if (!gasPrice) { return { @@ -35,7 +35,7 @@ export const calculateGasCost = ( : null return { - rawGasCost: estimatedGasCostInGwei, - parsedGasCost: formattedEstimatedGasCost, + rawGasCost: estimatedGasCostInGwei.toString(), + parsedGasCost: formattedEstimatedGasCost.toString(), } } From 52d65cee0b2aabb03dd25e973280e16434803657 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:00:52 -0700 Subject: [PATCH 045/143] Fix naming --- .../StateManagedBridge/InputContainer.tsx | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 66000626f8..847d1ac087 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -55,13 +55,7 @@ export const InputContainer = () => { (token) => token.tokenAddress === fromToken?.addresses[fromChainId] ) - const { balance: rawBalance, parsedBalance: trimmedParsedBalance } = - selectedFromToken || {} - - const parsedBalance: string = formatBigIntToString( - rawBalance, - fromToken?.decimals[fromChainId] - ) + const { balance, parsedBalance } = selectedFromToken || {} useEffect(() => { setHasMounted(true) @@ -117,7 +111,7 @@ export const InputContainer = () => { const onMaxBalance = () => { dispatch( updateFromValue( - formatBigIntToString(rawBalance, fromToken?.decimals[fromChainId]) + formatBigIntToString(balance, fromToken?.decimals[fromChainId]) ) ) } @@ -149,7 +143,7 @@ export const InputContainer = () => { } else { dispatch( updateFromValue( - formatBigIntToString(rawBalance, fromToken?.decimals[fromChainId]) + formatBigIntToString(balance, fromToken?.decimals[fromChainId]) ) ) } @@ -158,8 +152,8 @@ export const InputContainer = () => { fromToken, isGasToken, parsedGasCost, - rawBalance, - trimmedParsedBalance, + balance, + parsedBalance, ]) const showMaxButton = (): boolean => { @@ -196,8 +190,8 @@ export const InputContainer = () => { } const isTraceBalance = (): boolean => { - if (!rawBalance || !trimmedParsedBalance) return false - if (rawBalance && hasOnlyZeroes(trimmedParsedBalance)) return true + if (!balance || !parsedBalance) return false + if (balance && hasOnlyZeroes(parsedBalance)) return true return false } @@ -221,7 +215,7 @@ export const InputContainer = () => { /> { {hasMounted && isConnected && ( )} @@ -306,16 +300,46 @@ const AvailableBalance = ({ return false } + const isGasCostCovered = (): boolean => { + if (!isGasToken) return true + + if (isGasToken && parsedGasCost && fromValue && parsedBalance) { + return ( + parseFloat(fromValue) > + parseFloat(parsedBalance) - parseFloat(parsedGasCost) + ) + } + + return true + } + + const isGasBalanceLessThanCost = (): boolean => { + if (isGasToken && parsedGasCost && parsedBalance) { + return parseFloat(parsedGasCost) > parseFloat(parsedBalance) + } else { + return false + } + } + if (hasMounted && isConnected && !disabled) { return ( - + + ) } return null From d7b073bf7a9fc4b926f6992ef74538273f7f3dc7 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:08:06 -0700 Subject: [PATCH 046/143] Add HoverTooltip to Available Balance --- .../StateManagedBridge/AvailableBalance.tsx | 83 +++++++++++++++++++ .../StateManagedBridge/InputContainer.tsx | 11 ++- 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx diff --git a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx new file mode 100644 index 0000000000..34673c4b4e --- /dev/null +++ b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx @@ -0,0 +1,83 @@ +import React from 'react' +import { hasOnlyZeroes } from '@/utils/hasOnlyZeroes' +import { joinClassNames } from '@/utils/joinClassNames' +import { HoverTooltip } from './InputContainer' + +export const AvailableBalance = ({ + fromValue, + balance, + parsedBalance, + isGasToken = false, + parsedGasCost, + onMaxBalance, + hasMounted, + isConnected, + disabled = false, +}: { + fromValue: string + balance?: bigint + parsedBalance?: string + isGasToken?: boolean + parsedGasCost?: string + onMaxBalance?: () => void + hasMounted: boolean + isConnected: boolean + disabled?: boolean +}) => { + const labelClassName = joinClassNames({ + space: 'block', + textColor: 'text-xxs md:text-xs', + animation: 'transition-all duration-150 transform-gpu', + hover: 'hover:opacity-70 cursor-pointer', + }) + + const isTraceBalance = (): boolean => { + if (!balance || !parsedBalance) return false + if (balance && hasOnlyZeroes(parsedBalance)) return true + return false + } + + const isGasCostCovered = (): boolean => { + if (!isGasToken) return true + + if (isGasToken && parsedGasCost && fromValue && parsedBalance) { + return ( + parseFloat(fromValue) > + parseFloat(parsedBalance) - parseFloat(parsedGasCost) + ) + } + + return true + } + + const isGasBalanceLessThanCost = (): boolean => { + if (isGasToken && parsedGasCost && parsedBalance) { + return parseFloat(parsedGasCost) > parseFloat(parsedBalance) + } else { + return false + } + } + + if (hasMounted && isConnected && !disabled) { + return ( + + Gas fees may exceed your available balance + + } + > + + + ) + } + return null +} diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 847d1ac087..e8ba9eba6a 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -47,7 +47,7 @@ export const InputContainer = () => { const { gasData } = useAppSelector((state) => state.gasData) const { gasPrice, maxFeePerGas } = gasData?.formatted - const { rawGasCost, parsedGasCost } = calculateGasCost(gasPrice, 200_000) + const { rawGasCost, parsedGasCost } = calculateGasCost(gasPrice, 500_000) const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress @@ -189,6 +189,8 @@ export const InputContainer = () => { } } + console.log('isGasBalanceLessThanCost outside:', isGasBalanceLessThanCost()) + const isTraceBalance = (): boolean => { if (!balance || !parsedBalance) return false if (balance && hasOnlyZeroes(parsedBalance)) return true @@ -217,6 +219,7 @@ export const InputContainer = () => { fromValue={fromValue} balance={balance} parsedBalance={parsedBalance} + isGasToken={isGasToken} parsedGasCost={parsedGasCost} onMaxBalance={onMaxBalance} isConnected={isConnected} @@ -300,7 +303,7 @@ const AvailableBalance = ({ return false } - const isGasCostCovered = (): boolean => { + const isGasCostCoveredByInput = (): boolean => { if (!isGasToken) return true if (isGasToken && parsedGasCost && fromValue && parsedBalance) { @@ -321,10 +324,12 @@ const AvailableBalance = ({ } } + console.log('isGasBalanceLessThanCost inside:', isGasBalanceLessThanCost()) + if (hasMounted && isConnected && !disabled) { return ( Gas fees may exceed your available balance From e34a363bac17d72508c6bccd96575f8c5d928f69 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:15:00 -0700 Subject: [PATCH 047/143] Add conditions for displaying gas error based on input --- .../StateManagedBridge/InputContainer.tsx | 55 +++++++++---------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index e8ba9eba6a..dba5cd3d11 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -181,22 +181,6 @@ export const InputContainer = () => { } } - const isGasBalanceLessThanCost = (): boolean => { - if (isGasToken && parsedGasCost && parsedBalance) { - return parseFloat(parsedGasCost) > parseFloat(parsedBalance) - } else { - return false - } - } - - console.log('isGasBalanceLessThanCost outside:', isGasBalanceLessThanCost()) - - const isTraceBalance = (): boolean => { - if (!balance || !parsedBalance) return false - if (balance && hasOnlyZeroes(parsedBalance)) return true - return false - } - return (
@@ -304,37 +288,48 @@ const AvailableBalance = ({ } const isGasCostCoveredByInput = (): boolean => { - if (!isGasToken) return true - if (isGasToken && parsedGasCost && fromValue && parsedBalance) { return ( - parseFloat(fromValue) > + parseFloat(fromValue) < parseFloat(parsedBalance) - parseFloat(parsedGasCost) ) + } else { + return true } - - return true } - const isGasBalanceLessThanCost = (): boolean => { + const isGasCostCoveredByBalance = (): boolean => { if (isGasToken && parsedGasCost && parsedBalance) { - return parseFloat(parsedGasCost) > parseFloat(parsedBalance) + return parseFloat(parsedGasCost) < parseFloat(parsedBalance) } else { return false } } - console.log('isGasBalanceLessThanCost inside:', isGasBalanceLessThanCost()) + let tooltipContent + + if (!isGasCostCoveredByInput()) { + tooltipContent = ( +
+ You may not have enough to cover gas fees. +
+ ) + } else if (!isGasCostCoveredByBalance()) { + tooltipContent = ( +
+ Gas fees may exceed your available balance. +
+ ) + } + + console.log('isGasCostCoveredByInput: ', isGasCostCoveredByInput()) + console.log('isGasCostCoveredByBalance:', isGasCostCoveredByBalance()) if (hasMounted && isConnected && !disabled) { return ( - Gas fees may exceed your available balance -
- } + isActive={!isGasCostCoveredByBalance() || !isGasCostCoveredByInput()} + hoverContent={tooltipContent} >
-// -// ))} From 89a386f0ee1633968ceba8af75109849d23188c0 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:55:24 -0700 Subject: [PATCH 054/143] Fetch estimated gas limit based on real bridge quote using max gas balance --- .../StateManagedBridge/InputContainer.tsx | 111 +++++++++++++++++- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 30ef016a3c..e69faade64 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -1,6 +1,6 @@ import { isNull } from 'lodash' import { useAppSelector, useAppDispatch } from '@/store/hooks' -import { zeroAddress } from 'viem' +import { zeroAddress, Address } from 'viem' import { initialState, updateFromValue, @@ -35,15 +35,81 @@ import MiniMaxButton from '../buttons/MiniMaxButton' import { joinClassNames } from '@/utils/joinClassNames' import { Token } from '@/utils/types' import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterDecimal' +import { stringToBigInt } from '@/utils/bigint/format' +import { getPublicClient } from '@wagmi/core' +import { useSynapseContext } from '@/utils/providers/SynapseProvider' export const inputRef = React.createRef() +const getBridgeQuote = async ( + synapseSDK: any, + fromChainId: number, + toChainId: number, + fromToken: Token, + toToken: Token, + amount: string +) => { + return await synapseSDK.bridgeQuote( + fromChainId, + toChainId, + fromToken.addresses[fromChainId], + toToken.addresses[toChainId], + stringToBigInt(amount, fromToken?.decimals[fromChainId]) + ) +} + +const calculateEstimatedBridgeGasLimit = async ( + synapseSDK: any, + bridgeQuote: any, + address: string, + toAddress: string, + fromChainId: number, + toChainId: number, + fromToken: Token, + amount: string +) => { + const data = await synapseSDK.bridge( + toAddress, + bridgeQuote.routerAddress, + fromChainId, + toChainId, + fromToken?.addresses[fromChainId as keyof Token['addresses']], + stringToBigInt(amount, fromToken?.decimals[fromChainId]), + bridgeQuote.originQuery, + bridgeQuote.destQuery + ) + + const payload = + fromToken?.addresses[fromChainId as keyof Token['addresses']] === + zeroAddress || + fromToken?.addresses[fromChainId as keyof Token['addresses']] === '' + ? { + data: data.data, + to: data.to, + value: stringToBigInt(amount, fromToken?.decimals[fromChainId]), + } + : data + + const publicClient = getPublicClient() + + const gasEstimate = await publicClient.estimateGas({ + value: payload.value, + to: payload.to, + account: address as Address, + data: payload.data, + chainId: fromChainId, + }) + + return gasEstimate +} + export const InputContainer = () => { const dispatch = useAppDispatch() const { chain } = useNetwork() - const { isConnected } = useAccount() + const { address, isConnected } = useAccount() const { balances } = usePortfolioState() - const { fromChainId, fromToken, fromValue } = useBridgeState() + const { fromChainId, toChainId, fromToken, toToken, fromValue } = + useBridgeState() const [showValue, setShowValue] = useState('') const [hasMounted, setHasMounted] = useState(false) @@ -59,6 +125,43 @@ export const InputContainer = () => { const { balance, parsedBalance } = selectedFromToken || {} + const { synapseSDK } = useSynapseContext() + + useEffect(() => { + if ( + fromChainId && + toChainId && + fromToken && + toToken && + address && + isGasToken + ) { + ;(async () => { + const bridgeQuote = await getBridgeQuote( + synapseSDK, + fromChainId, + toChainId, + fromToken, + toToken, + parsedBalance + ) + + const gasLimit = await calculateEstimatedBridgeGasLimit( + synapseSDK, + bridgeQuote, + address, + address, + fromChainId, + toChainId, + fromToken, + parsedBalance + ) + + console.log('gasLimit: ', gasLimit) + })() + } + }, [fromChainId, toChainId, fromToken, toToken, address, isGasToken]) + useEffect(() => { setHasMounted(true) }, []) @@ -346,8 +449,6 @@ const AvailableBalance = ({ onClick={onMaxBalance} className={labelClassName} > - {/* {parseFloat(parsedGasCost).toFixed(4)} */} - {/* estimated gas required */} {isTraceInput() ? '<0.001' : gasReserved.toFixed(4)} reserved for gas From f3bd4f1a636b8c9af877ae0d03c2dd710a43f5d6 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:00:30 -0700 Subject: [PATCH 055/143] Fetching accurate gasLimit --- .../StateManagedBridge/InputContainer.tsx | 15 ++++++++++++--- .../synapse-interface/utils/calculateGasCost.ts | 12 ++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index e69faade64..bd905fade5 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -113,9 +113,14 @@ export const InputContainer = () => { const [showValue, setShowValue] = useState('') const [hasMounted, setHasMounted] = useState(false) + const [estimatedGasLimit, setEstimatedGasLimit] = useState(0n) + const { gasData } = useAppSelector((state) => state.gasData) const { gasPrice, maxFeePerGas } = gasData?.formatted - const { rawGasCost, parsedGasCost } = calculateGasCost(gasPrice, 500_000) + const { rawGasCost, parsedGasCost } = calculateGasCost( + gasPrice, + estimatedGasLimit.toString() + ) const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress @@ -125,8 +130,9 @@ export const InputContainer = () => { const { balance, parsedBalance } = selectedFromToken || {} - const { synapseSDK } = useSynapseContext() + /** Fetch gasLimit using Wallet's gas balance */ + const { synapseSDK } = useSynapseContext() useEffect(() => { if ( fromChainId && @@ -134,7 +140,8 @@ export const InputContainer = () => { fromToken && toToken && address && - isGasToken + isGasToken && + parsedBalance ) { ;(async () => { const bridgeQuote = await getBridgeQuote( @@ -157,6 +164,8 @@ export const InputContainer = () => { parsedBalance ) + setEstimatedGasLimit(gasLimit) + console.log('gasLimit: ', gasLimit) })() } diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts index c4c2c41dbc..c95380bce3 100644 --- a/packages/synapse-interface/utils/calculateGasCost.ts +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -10,13 +10,13 @@ import { formatGwei } from 'viem' */ export const calculateGasCost = ( - gasPrice?: string, - gasLimit = 200000 + gasPrice: string | undefined, + gasLimit: string ): { rawGasCost: string parsedGasCost: string } => { - if (!gasPrice) { + if (!gasPrice || !gasLimit) { return { rawGasCost: null, parsedGasCost: null, @@ -26,7 +26,7 @@ export const calculateGasCost = ( const upperLimitBuffer = 1.5 const estimatedGasCostInGwei = - gasLimit * parseFloat(gasPrice) * upperLimitBuffer + parseFloat(gasLimit) * parseFloat(gasPrice) * upperLimitBuffer const oneGwei = parseFloat(formatGwei(1n)) @@ -35,7 +35,7 @@ export const calculateGasCost = ( : null return { - rawGasCost: estimatedGasCostInGwei.toString(), - parsedGasCost: formattedEstimatedGasCost.toString(), + rawGasCost: estimatedGasCostInGwei?.toString(), + parsedGasCost: formattedEstimatedGasCost?.toString(), } } From 7d75555acc7237a2d93680342d8f2d7b7fc49a1d Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:11:23 -0700 Subject: [PATCH 056/143] Fix Trace balance --- .../components/StateManagedBridge/InputContainer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index bd905fade5..fcc351838d 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -367,7 +367,7 @@ const AvailableBalance = ({ const isTraceBalance = (): boolean => { if (!balance || !parsedBalanceFull) return false - if (balance && hasOnlyZeroes(parsedBalanceFull)) return true + if (balance && !hasOnlyZeroes(parsedBalanceFull)) return true return false } From ec90bd0e4e0c7d10604d262256ec447561bfab77 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:15:49 -0700 Subject: [PATCH 057/143] Set gasLimit to 0 if not valid bridge data avail --- .../StateManagedBridge/InputContainer.tsx | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index fcc351838d..0f1d6ee04f 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -49,18 +49,23 @@ const getBridgeQuote = async ( toToken: Token, amount: string ) => { - return await synapseSDK.bridgeQuote( - fromChainId, - toChainId, - fromToken.addresses[fromChainId], - toToken.addresses[toChainId], - stringToBigInt(amount, fromToken?.decimals[fromChainId]) - ) + try { + return await synapseSDK.bridgeQuote( + fromChainId, + toChainId, + fromToken.addresses[fromChainId], + toToken.addresses[toChainId], + stringToBigInt(amount, fromToken?.decimals[fromChainId]) + ) + } catch (error) { + console.error('getBridgeQuote: ', error) + return null + } } const calculateEstimatedBridgeGasLimit = async ( synapseSDK: any, - bridgeQuote: any, + bridgeQuote: any | null, address: string, toAddress: string, fromChainId: number, @@ -68,6 +73,8 @@ const calculateEstimatedBridgeGasLimit = async ( fromToken: Token, amount: string ) => { + if (!bridgeQuote) return null + const data = await synapseSDK.bridge( toAddress, bridgeQuote.routerAddress, @@ -122,6 +129,10 @@ export const InputContainer = () => { estimatedGasLimit.toString() ) + console.log('estimatedGasLimit:', estimatedGasLimit) + + console.log('parsedGasCost: ', parsedGasCost) + const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( @@ -164,7 +175,7 @@ export const InputContainer = () => { parsedBalance ) - setEstimatedGasLimit(gasLimit) + setEstimatedGasLimit(gasLimit ?? 0n) console.log('gasLimit: ', gasLimit) })() From a2b8f645a573f1a9856266b45751da0124d784e9 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:52:24 -0700 Subject: [PATCH 058/143] ... --- .../components/StateManagedBridge/InputContainer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 0f1d6ee04f..f64c351179 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -393,7 +393,7 @@ const AvailableBalance = ({ } const isGasCostCoveredByInput = (): boolean => { - if (!isGasToken) return true + if (!isGasToken && !parsedGasCost) return true if (isGasToken && parsedGasCost && fromValue && parsedBalanceFull) { return ( From 509f66a494d471e37e6772498567a2bb48477c4d Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:19:51 -0700 Subject: [PATCH 059/143] Fix when gas covered msg appears --- .../components/StateManagedBridge/InputContainer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index f64c351179..c10ce5dd95 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -406,12 +406,12 @@ const AvailableBalance = ({ } const isGasCostCoveredByBalance = (): boolean => { - if (!isGasToken) return true + if (!isGasToken && !parsedGasCost) return true if (isGasToken && parsedGasCost && parsedBalanceFull) { return parseFloat(parsedGasCost) < parseFloat(parsedBalanceFull) } else { - return false + return true } } From ef9d11c5f636669106e949e990b0a5e50e6a9558 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:41:14 -0700 Subject: [PATCH 060/143] Available Balance --- .../StateManagedBridge/AvailableBalance.tsx | 118 +++++++++++--- .../StateManagedBridge/InputContainer.tsx | 154 +----------------- 2 files changed, 94 insertions(+), 178 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx index 34673c4b4e..05f97d6806 100644 --- a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx @@ -2,9 +2,13 @@ import React from 'react' import { hasOnlyZeroes } from '@/utils/hasOnlyZeroes' import { joinClassNames } from '@/utils/joinClassNames' import { HoverTooltip } from './InputContainer' +import { Token } from '@/utils/types' +import { formatBigIntToString } from '@/utils/bigint/format' export const AvailableBalance = ({ + fromChainId, fromValue, + fromToken, balance, parsedBalance, isGasToken = false, @@ -14,7 +18,9 @@ export const AvailableBalance = ({ isConnected, disabled = false, }: { + fromChainId: number | null fromValue: string + fromToken: Token | null balance?: bigint parsedBalance?: string isGasToken?: boolean @@ -24,49 +30,110 @@ export const AvailableBalance = ({ isConnected: boolean disabled?: boolean }) => { - const labelClassName = joinClassNames({ - space: 'block', - textColor: 'text-xxs md:text-xs', - animation: 'transition-all duration-150 transform-gpu', - hover: 'hover:opacity-70 cursor-pointer', - }) + const parsedBalanceFull = formatBigIntToString( + balance, + fromToken?.decimals[fromChainId] + ) const isTraceBalance = (): boolean => { - if (!balance || !parsedBalance) return false - if (balance && hasOnlyZeroes(parsedBalance)) return true + if (!balance || !parsedBalanceFull) return false + if (balance && !hasOnlyZeroes(parsedBalanceFull)) return true return false } - const isGasCostCovered = (): boolean => { - if (!isGasToken) return true + const isTraceInput = (): boolean => { + if (!fromValue) return false + const shortenedFromValue = parseFloat(fromValue).toFixed(4) + if (Number(shortenedFromValue) === 0 && !hasOnlyZeroes(fromValue)) { + return true + } else { + return false + } + } - if (isGasToken && parsedGasCost && fromValue && parsedBalance) { + const isGasCostCoveredByInput = (): boolean => { + if (!isGasToken && !parsedGasCost) return true + + if (isGasToken && parsedGasCost && fromValue && parsedBalanceFull) { return ( parseFloat(fromValue) > - parseFloat(parsedBalance) - parseFloat(parsedGasCost) + parseFloat(parsedBalanceFull) - parseFloat(parsedGasCost) ) + } else { + return true } - - return true } - const isGasBalanceLessThanCost = (): boolean => { - if (isGasToken && parsedGasCost && parsedBalance) { - return parseFloat(parsedGasCost) > parseFloat(parsedBalance) + const isGasCostCoveredByBalance = (): boolean => { + if (!isGasToken) return true + + if (isGasToken && parsedGasCost && parsedBalanceFull) { + return parseFloat(parsedGasCost) < parseFloat(parsedBalanceFull) } else { return false } } - if (hasMounted && isConnected && !disabled) { + const showGasReserved = (): boolean => { + return !hasOnlyZeroes(fromValue) && !isGasCostCoveredByInput() + } + + const gasReserved = showGasReserved() + ? isGasCostCoveredByBalance() + ? parseFloat(parsedGasCost) + : parseFloat(fromValue) + : undefined + + let tooltipContent + + if (showGasReserved()) { + tooltipContent = ( +
+
You may not have enough to cover gas fees.
+
Estimated gas: {parseFloat(parsedGasCost).toFixed(4)}
+
+ ) + } else if (!isGasCostCoveredByInput()) { + tooltipContent = ( +
+ You may not have enough to cover gas fees. +
+ ) + } else if (!isGasCostCoveredByBalance()) { + tooltipContent = ( +
+ Gas fees may exceed your available balance. +
+ ) + } + + const labelClassName = joinClassNames({ + space: 'block', + textColor: `text-xxs md:text-xs ${ + showGasReserved() ? '!text-yellowText' : '' + }`, + animation: 'transition-all duration-150 transform-gpu', + hover: 'hover:opacity-70 cursor-pointer', + }) + + if (showGasReserved()) { + return ( + + + + ) + } else if (hasMounted && isConnected && !disabled) { return ( - Gas fees may exceed your available balance - - } + isActive={!isGasCostCoveredByBalance() || !isGasCostCoveredByInput()} + hoverContent={tooltipContent} > ) + } else { + return null } - return null } diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index c10ce5dd95..ade88cb12f 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -38,6 +38,7 @@ import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterD import { stringToBigInt } from '@/utils/bigint/format' import { getPublicClient } from '@wagmi/core' import { useSynapseContext } from '@/utils/providers/SynapseProvider' +import { AvailableBalance } from './AvailableBalance' export const inputRef = React.createRef() @@ -129,10 +130,6 @@ export const InputContainer = () => { estimatedGasLimit.toString() ) - console.log('estimatedGasLimit:', estimatedGasLimit) - - console.log('parsedGasCost: ', parsedGasCost) - const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( @@ -346,155 +343,6 @@ const FromTokenSelector = () => { ) } -const AvailableBalance = ({ - fromChainId, - fromValue, - fromToken, - balance, - parsedBalance, - isGasToken = false, - parsedGasCost, - onMaxBalance, - hasMounted, - isConnected, - disabled = false, -}: { - fromChainId: number | null - fromValue: string - fromToken: Token | null - balance?: bigint - parsedBalance?: string - isGasToken?: boolean - parsedGasCost?: string - onMaxBalance?: () => void - hasMounted: boolean - isConnected: boolean - disabled?: boolean -}) => { - const parsedBalanceFull = formatBigIntToString( - balance, - fromToken?.decimals[fromChainId] - ) - - const isTraceBalance = (): boolean => { - if (!balance || !parsedBalanceFull) return false - if (balance && !hasOnlyZeroes(parsedBalanceFull)) return true - return false - } - - const isTraceInput = (): boolean => { - if (!fromValue) return false - const shortenedFromValue = parseFloat(fromValue).toFixed(4) - if (Number(shortenedFromValue) === 0 && !hasOnlyZeroes(fromValue)) { - return true - } else { - return false - } - } - - const isGasCostCoveredByInput = (): boolean => { - if (!isGasToken && !parsedGasCost) return true - - if (isGasToken && parsedGasCost && fromValue && parsedBalanceFull) { - return ( - parseFloat(fromValue) < - parseFloat(parsedBalanceFull) - parseFloat(parsedGasCost) - ) - } else { - return true - } - } - - const isGasCostCoveredByBalance = (): boolean => { - if (!isGasToken && !parsedGasCost) return true - - if (isGasToken && parsedGasCost && parsedBalanceFull) { - return parseFloat(parsedGasCost) < parseFloat(parsedBalanceFull) - } else { - return true - } - } - - const showGasReserved = (): boolean => { - return !hasOnlyZeroes(fromValue) && !isGasCostCoveredByInput() - } - - const gasReserved = showGasReserved() - ? isGasCostCoveredByBalance() - ? parseFloat(fromValue) - parseFloat(parsedGasCost) - : parseFloat(fromValue) - : undefined - - let tooltipContent - - if (showGasReserved()) { - tooltipContent = ( -
-
You may not have enough to cover gas fees.
-
Estimated gas: {parseFloat(parsedGasCost).toFixed(4)}
-
- ) - } else if (!isGasCostCoveredByInput()) { - tooltipContent = ( -
- You may not have enough to cover gas fees. -
- ) - } else if (!isGasCostCoveredByBalance()) { - tooltipContent = ( -
- Gas fees may exceed your available balance. -
- ) - } - - const labelClassName = joinClassNames({ - space: 'block', - textColor: `text-xxs md:text-xs ${ - showGasReserved() ? '!text-yellowText' : '' - }`, - animation: 'transition-all duration-150 transform-gpu', - hover: 'hover:opacity-70 cursor-pointer', - }) - - // console.log('showGasReserved:', showGasReserved()) - // console.log('isGasCostCoveredByInput: ', isGasCostCoveredByInput()) - // console.log('isGasCostCoveredByBalance:', isGasCostCoveredByBalance()) - - if (showGasReserved()) { - return ( - - - - ) - } else if (hasMounted && isConnected && !disabled) { - return ( - - - - ) - } else { - return null - } -} - // TODO: Replace with HoverTooltip in Portfolio once other branch is merged in export const HoverTooltip = ({ children, hoverContent, isActive }) => { const [showTooltip, setShowTooltip] = useState(false) From 8b23f184f53f62106d9362ee82bc5b561e5096a3 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:54:38 -0700 Subject: [PATCH 061/143] Clean available balance flow --- .../StateManagedBridge/AvailableBalance.tsx | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx index 05f97d6806..7c34b3966d 100644 --- a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx @@ -4,6 +4,7 @@ import { joinClassNames } from '@/utils/joinClassNames' import { HoverTooltip } from './InputContainer' import { Token } from '@/utils/types' import { formatBigIntToString } from '@/utils/bigint/format' +import { isUndefined } from 'lodash' export const AvailableBalance = ({ fromChainId, @@ -36,41 +37,38 @@ export const AvailableBalance = ({ ) const isTraceBalance = (): boolean => { - if (!balance || !parsedBalanceFull) return false - if (balance && !hasOnlyZeroes(parsedBalanceFull)) return true - return false + if (balance && !hasOnlyZeroes(parsedBalanceFull)) { + return true + } else { + return false + } } const isTraceInput = (): boolean => { - if (!fromValue) return false - const shortenedFromValue = parseFloat(fromValue).toFixed(4) - if (Number(shortenedFromValue) === 0 && !hasOnlyZeroes(fromValue)) { - return true - } else { + if (!fromValue) { return false + } else { + const shortenedFromValue = parseFloat(fromValue).toFixed(4) + return Number(shortenedFromValue) === 0 && !hasOnlyZeroes(fromValue) } } const isGasCostCoveredByInput = (): boolean => { - if (!isGasToken && !parsedGasCost) return true - - if (isGasToken && parsedGasCost && fromValue && parsedBalanceFull) { + if (!isGasToken || !parsedGasCost || !parsedBalanceFull || !fromValue) { + return true + } else { return ( parseFloat(fromValue) > parseFloat(parsedBalanceFull) - parseFloat(parsedGasCost) ) - } else { - return true } } const isGasCostCoveredByBalance = (): boolean => { - if (!isGasToken) return true - - if (isGasToken && parsedGasCost && parsedBalanceFull) { - return parseFloat(parsedGasCost) < parseFloat(parsedBalanceFull) + if (!isGasToken || !parsedGasCost || !parsedBalanceFull) { + return true } else { - return false + return parseFloat(parsedGasCost) < parseFloat(parsedBalanceFull) } } From cb16d7ae9bba05099cced8d31311b98884c2b6e3 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Thu, 11 Apr 2024 17:12:45 -0700 Subject: [PATCH 062/143] useGasEstimator hook to encapsulate logic to clean InputContainer --- .../StateManagedBridge/InputContainer.tsx | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index ade88cb12f..fa3495ec32 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -111,6 +111,74 @@ const calculateEstimatedBridgeGasLimit = async ( return gasEstimate } +const useGasEstimator = () => { + const { address } = useAccount() + const { synapseSDK } = useSynapseContext() + const { balances } = usePortfolioState() + const { fromChainId, toChainId, fromToken, toToken, fromValue } = + useBridgeState() + const { gasData } = useAppSelector((state) => state.gasData) + const { gasPrice, maxFeePerGas } = gasData?.formatted + + const [estimatedGasLimit, setEstimatedGasLimit] = useState(0n) + + const { rawGasCost, parsedGasCost } = calculateGasCost( + gasPrice, + estimatedGasLimit.toString() + ) + + const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress + + const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( + (token) => token.tokenAddress === fromToken?.addresses[fromChainId] + ) + + const { balance, parsedBalance } = selectedFromToken || {} + + const hasRequiredGasEstimateInputs = (): boolean => { + return Boolean( + fromChainId && + toChainId && + fromToken && + toToken && + isGasToken && + parsedBalance + ) + } + + useEffect(() => { + if (hasRequiredGasEstimateInputs()) { + ;(async () => { + const bridgeQuote = await getBridgeQuote( + synapseSDK, + fromChainId, + toChainId, + fromToken, + toToken, + parsedBalance + ) + + const gasLimit = await calculateEstimatedBridgeGasLimit( + synapseSDK, + bridgeQuote, + address, + address, + fromChainId, + toChainId, + fromToken, + parsedBalance + ) + + setEstimatedGasLimit(gasLimit ?? 0n) + + console.log('gasLimit: ', gasLimit) + })() + } + }, [fromChainId, toChainId, isGasToken]) + + return { rawGasCost, parsedGasCost } +} + export const InputContainer = () => { const dispatch = useAppDispatch() const { chain } = useNetwork() From 914d2374898dae535abf2d01707e98e609ceb5c4 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:34:54 -0700 Subject: [PATCH 063/143] Fix prop issue --- .../components/StateManagedSwap/SwapInputContainer.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx b/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx index 383cd07ac9..76ad88fe97 100644 --- a/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx @@ -117,12 +117,8 @@ export const SwapInputContainer = () => { {hasMounted && isConnected && ( From fb72b992e4eee12aeeb90851ddaf2050200a08b3 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:53:21 -0700 Subject: [PATCH 064/143] Remove duplicate HoverTooltip --- .../Portfolio/components/HoverTooltip.tsx | 34 +++++++++----- .../StateManagedBridge/AvailableBalance.tsx | 3 +- .../StateManagedBridge/InputContainer.tsx | 46 ------------------- 3 files changed, 24 insertions(+), 59 deletions(-) diff --git a/packages/synapse-interface/components/Portfolio/components/HoverTooltip.tsx b/packages/synapse-interface/components/Portfolio/components/HoverTooltip.tsx index 88e01b5999..dbe45c2576 100644 --- a/packages/synapse-interface/components/Portfolio/components/HoverTooltip.tsx +++ b/packages/synapse-interface/components/Portfolio/components/HoverTooltip.tsx @@ -1,21 +1,33 @@ import React, { useState } from 'react' -export const HoverTooltip = ({ children, hoverContent }) => { +export const HoverTooltip = ({ + children, + hoverContent, + isActive = true, +}: { + children: React.ReactNode + hoverContent: React.ReactNode + isActive?: boolean +}) => { const [showTooltip, setShowTooltip] = useState(false) const activateTooltip = () => setShowTooltip(true) const hideTooltip = () => setShowTooltip(false) - return ( -
- {children} - {hoverContent} -
- ) + if (!isActive) { + return
{children}
+ } else { + return ( +
+ {children} + {hoverContent} +
+ ) + } } const Tooltip = ({ diff --git a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx index 7c34b3966d..ebc9e40d0a 100644 --- a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx @@ -1,10 +1,9 @@ import React from 'react' import { hasOnlyZeroes } from '@/utils/hasOnlyZeroes' import { joinClassNames } from '@/utils/joinClassNames' -import { HoverTooltip } from './InputContainer' import { Token } from '@/utils/types' import { formatBigIntToString } from '@/utils/bigint/format' -import { isUndefined } from 'lodash' +import { HoverTooltip } from '../Portfolio/components/HoverTooltip' export const AvailableBalance = ({ fromChainId, diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 273e9a9d74..1e18b1f330 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -410,49 +410,3 @@ const FromTokenSelector = () => { /> ) } - -// TODO: Replace with HoverTooltip in Portfolio once other branch is merged in -export const HoverTooltip = ({ children, hoverContent, isActive }) => { - const [showTooltip, setShowTooltip] = useState(false) - - const activateTooltip = () => setShowTooltip(true) - const hideTooltip = () => setShowTooltip(false) - - if (!isActive) { - return
{children}
- } else { - return ( -
- {children} - {hoverContent} -
- ) - } -} - -const Tooltip = ({ - isHovered, - children, -}: { - isHovered: boolean - children: React.ReactNode -}) => { - if (isHovered) { - return ( -
- {children} -
- ) - } -} From 8377d7ac205d47a78db40508d9138a6b88ff17ae Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:55:04 -0700 Subject: [PATCH 065/143] Move HoverTooltip to shared component folder --- .../components/{Portfolio/components => }/HoverTooltip.tsx | 0 .../components/Portfolio/components/GasTokenAsset.tsx | 2 +- .../components/Portfolio/components/PortfolioTokenAsset.tsx | 2 +- .../Portfolio/components/PortfolioTokenVisualizer.tsx | 2 +- .../components/StateManagedBridge/AvailableBalance.tsx | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename packages/synapse-interface/components/{Portfolio/components => }/HoverTooltip.tsx (100%) diff --git a/packages/synapse-interface/components/Portfolio/components/HoverTooltip.tsx b/packages/synapse-interface/components/HoverTooltip.tsx similarity index 100% rename from packages/synapse-interface/components/Portfolio/components/HoverTooltip.tsx rename to packages/synapse-interface/components/HoverTooltip.tsx diff --git a/packages/synapse-interface/components/Portfolio/components/GasTokenAsset.tsx b/packages/synapse-interface/components/Portfolio/components/GasTokenAsset.tsx index 19e22d005c..cae8ccb317 100644 --- a/packages/synapse-interface/components/Portfolio/components/GasTokenAsset.tsx +++ b/packages/synapse-interface/components/Portfolio/components/GasTokenAsset.tsx @@ -2,7 +2,7 @@ import React from 'react' import Image from 'next/image' import { Token } from '@/utils/types' import { getParsedBalance } from '@/utils/getParsedBalance' -import { HoverTooltip } from './HoverTooltip' +import { HoverTooltip } from '../../HoverTooltip' import GasIcon from '@/components/icons/GasIcon' export const GasTokenAsset = ({ diff --git a/packages/synapse-interface/components/Portfolio/components/PortfolioTokenAsset.tsx b/packages/synapse-interface/components/Portfolio/components/PortfolioTokenAsset.tsx index be3b17044b..9bd236b4ed 100644 --- a/packages/synapse-interface/components/Portfolio/components/PortfolioTokenAsset.tsx +++ b/packages/synapse-interface/components/Portfolio/components/PortfolioTokenAsset.tsx @@ -14,7 +14,7 @@ import { PortfolioAssetActionButton } from './PortfolioAssetActionButton' import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterDecimal' import { zeroAddress } from 'viem' import GasIcon from '@/components/icons/GasIcon' -import { HoverTooltip } from './HoverTooltip' +import { HoverTooltip } from '../../HoverTooltip' import { getParsedBalance } from '@/utils/getParsedBalance' const handleFocusOnBridgeInput = () => { diff --git a/packages/synapse-interface/components/Portfolio/components/PortfolioTokenVisualizer.tsx b/packages/synapse-interface/components/Portfolio/components/PortfolioTokenVisualizer.tsx index 984f72197c..39d915f747 100644 --- a/packages/synapse-interface/components/Portfolio/components/PortfolioTokenVisualizer.tsx +++ b/packages/synapse-interface/components/Portfolio/components/PortfolioTokenVisualizer.tsx @@ -1,6 +1,6 @@ import Image from 'next/image' import { TokenAndBalance } from '@/utils/actions/fetchPortfolioBalances' -import { HoverTooltip } from './HoverTooltip' +import { HoverTooltip } from '../../HoverTooltip' export const PortfolioTokenVisualizer = ({ portfolioTokens, diff --git a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx index ebc9e40d0a..323bb53e0c 100644 --- a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx @@ -3,7 +3,7 @@ import { hasOnlyZeroes } from '@/utils/hasOnlyZeroes' import { joinClassNames } from '@/utils/joinClassNames' import { Token } from '@/utils/types' import { formatBigIntToString } from '@/utils/bigint/format' -import { HoverTooltip } from '../Portfolio/components/HoverTooltip' +import { HoverTooltip } from '../HoverTooltip' export const AvailableBalance = ({ fromChainId, From 3954eeeaddeb3bdf61e1576be0ff66b3787c242f Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 17 Apr 2024 16:35:52 -0700 Subject: [PATCH 066/143] Update gas fetch for wagmi v2, up limit to 1.7 --- .../StateManagedBridge/InputContainer.tsx | 166 ++++++++++-------- .../synapse-interface/slices/gasDataSlice.ts | 6 +- .../utils/calculateGasCost.ts | 3 +- 3 files changed, 97 insertions(+), 78 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 1e18b1f330..6d01078d9b 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -1,6 +1,6 @@ import { isNull } from 'lodash' import { useAppSelector, useAppDispatch } from '@/store/hooks' -import { zeroAddress, Address } from 'viem' +import { zeroAddress, Address, parseGwei } from 'viem' import { initialState, updateFromValue, @@ -39,6 +39,7 @@ import { stringToBigInt } from '@/utils/bigint/format' import { getPublicClient } from '@wagmi/core' import { useSynapseContext } from '@/utils/providers/SynapseProvider' import { AvailableBalance } from './AvailableBalance' +import { estimateGas } from '@wagmi/core' import { wagmiConfig } from '@/wagmiConfig' export const inputRef = React.createRef() @@ -99,9 +100,8 @@ const calculateEstimatedBridgeGasLimit = async ( } : data - const publicClient = getPublicClient(wagmiConfig) - - const gasEstimate = await publicClient.estimateGas({ + const gasEstimate = await estimateGas(wagmiConfig, { + // maxFeePerGas: parseGwei(Math.ceil(parseFloat(maxFeePerGas)).toString()), value: payload.value, to: payload.to, account: address as Address, @@ -109,76 +109,78 @@ const calculateEstimatedBridgeGasLimit = async ( chainId: fromChainId, }) + console.log('gasEstimate from fn: ', gasEstimate) + return gasEstimate } -const useGasEstimator = () => { - const { address } = useAccount() - const { synapseSDK } = useSynapseContext() - const { balances } = usePortfolioState() - const { fromChainId, toChainId, fromToken, toToken, fromValue } = - useBridgeState() - const { gasData } = useAppSelector((state) => state.gasData) - const { gasPrice, maxFeePerGas } = gasData?.formatted - - const [estimatedGasLimit, setEstimatedGasLimit] = useState(0n) - - const { rawGasCost, parsedGasCost } = calculateGasCost( - gasPrice, - estimatedGasLimit.toString() - ) - - const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress - - const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( - (token) => token.tokenAddress === fromToken?.addresses[fromChainId] - ) - - const { balance, parsedBalance } = selectedFromToken || {} - - const hasRequiredGasEstimateInputs = (): boolean => { - return Boolean( - fromChainId && - toChainId && - fromToken && - toToken && - isGasToken && - parsedBalance - ) - } - - useEffect(() => { - if (hasRequiredGasEstimateInputs()) { - ;(async () => { - const bridgeQuote = await getBridgeQuote( - synapseSDK, - fromChainId, - toChainId, - fromToken, - toToken, - parsedBalance - ) - - const gasLimit = await calculateEstimatedBridgeGasLimit( - synapseSDK, - bridgeQuote, - address, - address, - fromChainId, - toChainId, - fromToken, - parsedBalance - ) - - setEstimatedGasLimit(gasLimit ?? 0n) - - console.log('gasLimit: ', gasLimit) - })() - } - }, [fromChainId, toChainId, isGasToken]) - - return { rawGasCost, parsedGasCost } -} +// const useGasEstimator = () => { +// const { address } = useAccount() +// const { synapseSDK } = useSynapseContext() +// const { balances } = usePortfolioState() +// const { fromChainId, toChainId, fromToken, toToken, fromValue } = +// useBridgeState() +// const { gasData } = useAppSelector((state) => state.gasData) +// const { gasPrice, maxFeePerGas } = gasData?.formatted + +// const [estimatedGasLimit, setEstimatedGasLimit] = useState(0n) + +// const { rawGasCost, parsedGasCost } = calculateGasCost( +// maxFeePerGas, +// estimatedGasLimit.toString() +// ) + +// const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress + +// const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( +// (token) => token.tokenAddress === fromToken?.addresses[fromChainId] +// ) + +// const { balance, parsedBalance } = selectedFromToken || {} + +// const hasRequiredGasEstimateInputs = (): boolean => { +// return Boolean( +// fromChainId && +// toChainId && +// fromToken && +// toToken && +// isGasToken && +// parsedBalance +// ) +// } + +// useEffect(() => { +// if (hasRequiredGasEstimateInputs()) { +// ;(async () => { +// const bridgeQuote = await getBridgeQuote( +// synapseSDK, +// fromChainId, +// toChainId, +// fromToken, +// toToken, +// parsedBalance +// ) + +// const gasLimit = await calculateEstimatedBridgeGasLimit( +// synapseSDK, +// bridgeQuote, +// address, +// address, +// fromChainId, +// toChainId, +// fromToken, +// parsedBalance +// ) + +// setEstimatedGasLimit(gasLimit ?? 0n) + +// // console.log('gasLimit: ', gasLimit) +// })() +// } +// }, [fromChainId, toChainId, isGasToken]) + +// return { rawGasCost, parsedGasCost } +// } export const InputContainer = () => { const dispatch = useDispatch() @@ -194,10 +196,15 @@ export const InputContainer = () => { const { gasData } = useAppSelector((state) => state.gasData) const { gasPrice, maxFeePerGas } = gasData?.formatted const { rawGasCost, parsedGasCost } = calculateGasCost( - gasPrice, + maxFeePerGas, estimatedGasLimit.toString() ) + console.log('gasData:', gasData) + console.log('parsedGasCost:', parsedGasCost) + + // console.log('maxFeePerGas: ', maxFeePerGas) + const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( @@ -220,6 +227,7 @@ export const InputContainer = () => { parsedBalance ) { ;(async () => { + console.log('fire off useeffect') const bridgeQuote = await getBridgeQuote( synapseSDK, fromChainId, @@ -229,6 +237,8 @@ export const InputContainer = () => { parsedBalance ) + console.log('bridgeQuote: ', bridgeQuote) + const gasLimit = await calculateEstimatedBridgeGasLimit( synapseSDK, bridgeQuote, @@ -241,11 +251,17 @@ export const InputContainer = () => { ) setEstimatedGasLimit(gasLimit ?? 0n) - - console.log('gasLimit: ', gasLimit) })() } - }, [fromChainId, toChainId, fromToken, toToken, address, isGasToken]) + }, [ + fromChainId, + toChainId, + fromToken, + toToken, + address, + isGasToken, + maxFeePerGas, + ]) useEffect(() => { setHasMounted(true) diff --git a/packages/synapse-interface/slices/gasDataSlice.ts b/packages/synapse-interface/slices/gasDataSlice.ts index 232e342921..9bd6444d94 100644 --- a/packages/synapse-interface/slices/gasDataSlice.ts +++ b/packages/synapse-interface/slices/gasDataSlice.ts @@ -1,5 +1,7 @@ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' -import { fetchFeeData } from '@wagmi/core' +import { estimateFeesPerGas } from '@wagmi/core' + +import { wagmiConfig } from '@/wagmiConfig' export interface GasDataState { gasData: { @@ -16,7 +18,7 @@ export interface GasDataState { } const getGasData = async (chainId: number) => { - const feeData = await fetchFeeData({ + const feeData = await estimateFeesPerGas(wagmiConfig, { chainId, formatUnits: 'gwei', }) diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts index c95380bce3..9663a2a41a 100644 --- a/packages/synapse-interface/utils/calculateGasCost.ts +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -17,13 +17,14 @@ export const calculateGasCost = ( parsedGasCost: string } => { if (!gasPrice || !gasLimit) { + console.log('missing gas price or gas limit') return { rawGasCost: null, parsedGasCost: null, } } - const upperLimitBuffer = 1.5 + const upperLimitBuffer = 1.7 const estimatedGasCostInGwei = parseFloat(gasLimit) * parseFloat(gasPrice) * upperLimitBuffer From 2f618cc3a569cf769f3819e6d7ab0101c1458991 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:21:23 -0700 Subject: [PATCH 067/143] Estimated gas bridge quote fetched on load --- .../StateManagedBridge/InputContainer.tsx | 168 +++++++++--------- .../synapse-interface/slices/gasDataSlice.ts | 4 +- .../utils/calculateGasCost.ts | 2 +- 3 files changed, 84 insertions(+), 90 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 6d01078d9b..4824263f8f 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -101,7 +101,6 @@ const calculateEstimatedBridgeGasLimit = async ( : data const gasEstimate = await estimateGas(wagmiConfig, { - // maxFeePerGas: parseGwei(Math.ceil(parseFloat(maxFeePerGas)).toString()), value: payload.value, to: payload.to, account: address as Address, @@ -114,74 +113,6 @@ const calculateEstimatedBridgeGasLimit = async ( return gasEstimate } -// const useGasEstimator = () => { -// const { address } = useAccount() -// const { synapseSDK } = useSynapseContext() -// const { balances } = usePortfolioState() -// const { fromChainId, toChainId, fromToken, toToken, fromValue } = -// useBridgeState() -// const { gasData } = useAppSelector((state) => state.gasData) -// const { gasPrice, maxFeePerGas } = gasData?.formatted - -// const [estimatedGasLimit, setEstimatedGasLimit] = useState(0n) - -// const { rawGasCost, parsedGasCost } = calculateGasCost( -// maxFeePerGas, -// estimatedGasLimit.toString() -// ) - -// const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress - -// const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( -// (token) => token.tokenAddress === fromToken?.addresses[fromChainId] -// ) - -// const { balance, parsedBalance } = selectedFromToken || {} - -// const hasRequiredGasEstimateInputs = (): boolean => { -// return Boolean( -// fromChainId && -// toChainId && -// fromToken && -// toToken && -// isGasToken && -// parsedBalance -// ) -// } - -// useEffect(() => { -// if (hasRequiredGasEstimateInputs()) { -// ;(async () => { -// const bridgeQuote = await getBridgeQuote( -// synapseSDK, -// fromChainId, -// toChainId, -// fromToken, -// toToken, -// parsedBalance -// ) - -// const gasLimit = await calculateEstimatedBridgeGasLimit( -// synapseSDK, -// bridgeQuote, -// address, -// address, -// fromChainId, -// toChainId, -// fromToken, -// parsedBalance -// ) - -// setEstimatedGasLimit(gasLimit ?? 0n) - -// // console.log('gasLimit: ', gasLimit) -// })() -// } -// }, [fromChainId, toChainId, isGasToken]) - -// return { rawGasCost, parsedGasCost } -// } - export const InputContainer = () => { const dispatch = useDispatch() const { address, chain, isConnected } = useAccount() @@ -200,11 +131,6 @@ export const InputContainer = () => { estimatedGasLimit.toString() ) - console.log('gasData:', gasData) - console.log('parsedGasCost:', parsedGasCost) - - // console.log('maxFeePerGas: ', maxFeePerGas) - const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( @@ -213,21 +139,21 @@ export const InputContainer = () => { const { balance, parsedBalance } = selectedFromToken || {} - /** Fetch gasLimit using Wallet's gas balance */ + const hasRequiredGasEstimateInputs = (): boolean => { + if (!fromChainId || !toChainId) return false + if (!fromToken || !toToken) return false + if (!isGasToken) return false + if (!parsedBalance) return false + return true + } + /** Fetch gasLimit using Wallet's gas balance */ const { synapseSDK } = useSynapseContext() + useEffect(() => { - if ( - fromChainId && - toChainId && - fromToken && - toToken && - address && - isGasToken && - parsedBalance - ) { + console.log('parsedBalance: ', parsedBalance) + if (hasRequiredGasEstimateInputs()) { ;(async () => { - console.log('fire off useeffect') const bridgeQuote = await getBridgeQuote( synapseSDK, fromChainId, @@ -256,11 +182,11 @@ export const InputContainer = () => { }, [ fromChainId, toChainId, + isGasToken, + selectedFromToken, fromToken, toToken, address, - isGasToken, - maxFeePerGas, ]) useEffect(() => { @@ -426,3 +352,71 @@ const FromTokenSelector = () => { /> ) } + +// const useGasEstimator = () => { +// const { address } = useAccount() +// const { synapseSDK } = useSynapseContext() +// const { balances } = usePortfolioState() +// const { fromChainId, toChainId, fromToken, toToken, fromValue } = +// useBridgeState() +// const { gasData } = useAppSelector((state) => state.gasData) +// const { gasPrice, maxFeePerGas } = gasData?.formatted + +// const [estimatedGasLimit, setEstimatedGasLimit] = useState(0n) + +// const { rawGasCost, parsedGasCost } = calculateGasCost( +// maxFeePerGas, +// estimatedGasLimit.toString() +// ) + +// const isGasToken: boolean = fromToken?.addresses[fromChainId] === zeroAddress + +// const selectedFromToken: TokenAndBalance = balances[fromChainId]?.find( +// (token) => token.tokenAddress === fromToken?.addresses[fromChainId] +// ) + +// const { balance, parsedBalance } = selectedFromToken || {} + +// const hasRequiredGasEstimateInputs = (): boolean => { +// return Boolean( +// fromChainId && +// toChainId && +// fromToken && +// toToken && +// isGasToken && +// parsedBalance +// ) +// } + +// useEffect(() => { +// if (hasRequiredGasEstimateInputs()) { +// ;(async () => { +// const bridgeQuote = await getBridgeQuote( +// synapseSDK, +// fromChainId, +// toChainId, +// fromToken, +// toToken, +// parsedBalance +// ) + +// const gasLimit = await calculateEstimatedBridgeGasLimit( +// synapseSDK, +// bridgeQuote, +// address, +// address, +// fromChainId, +// toChainId, +// fromToken, +// parsedBalance +// ) + +// setEstimatedGasLimit(gasLimit ?? 0n) + +// // console.log('gasLimit: ', gasLimit) +// })() +// } +// }, [fromChainId, toChainId, isGasToken]) + +// return { rawGasCost, parsedGasCost } +// } diff --git a/packages/synapse-interface/slices/gasDataSlice.ts b/packages/synapse-interface/slices/gasDataSlice.ts index 9bd6444d94..603c456cb8 100644 --- a/packages/synapse-interface/slices/gasDataSlice.ts +++ b/packages/synapse-interface/slices/gasDataSlice.ts @@ -5,11 +5,11 @@ import { wagmiConfig } from '@/wagmiConfig' export interface GasDataState { gasData: { - gasPrice: bigint + gasPrice?: bigint maxFeePerGas: bigint maxPriorityFeePerGas: bigint formatted: { - gasPrice: string + gasPrice?: string maxFeePerGas: string maxPriorityFeePerGas: string } diff --git a/packages/synapse-interface/utils/calculateGasCost.ts b/packages/synapse-interface/utils/calculateGasCost.ts index 9663a2a41a..c52e120109 100644 --- a/packages/synapse-interface/utils/calculateGasCost.ts +++ b/packages/synapse-interface/utils/calculateGasCost.ts @@ -24,7 +24,7 @@ export const calculateGasCost = ( } } - const upperLimitBuffer = 1.7 + const upperLimitBuffer = 1.5 const estimatedGasCostInGwei = parseFloat(gasLimit) * parseFloat(gasPrice) * upperLimitBuffer From e25cd3e8b8036c08c2570111a8b1365541542693 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:52:36 -0700 Subject: [PATCH 068/143] Update var naming --- .../StateManagedBridge/AvailableBalance.tsx | 23 ++++++++++++------- .../StateManagedBridge/InputContainer.tsx | 11 +-------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx index 323bb53e0c..47d9b64a4f 100644 --- a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx @@ -52,7 +52,7 @@ export const AvailableBalance = ({ } } - const isGasCostCoveredByInput = (): boolean => { + const isInputGreaterThanBalanceMinusGasFees = (): boolean => { if (!isGasToken || !parsedGasCost || !parsedBalanceFull || !fromValue) { return true } else { @@ -63,7 +63,7 @@ export const AvailableBalance = ({ } } - const isGasCostCoveredByBalance = (): boolean => { + const isBalanceGreaterThanGasFees = (): boolean => { if (!isGasToken || !parsedGasCost || !parsedBalanceFull) { return true } else { @@ -72,11 +72,14 @@ export const AvailableBalance = ({ } const showGasReserved = (): boolean => { - return !hasOnlyZeroes(fromValue) && !isGasCostCoveredByInput() + return ( + !hasOnlyZeroes(fromValue) && isGasToken + // !isInputGreaterThanBalanceMinusGasFees() + ) } const gasReserved = showGasReserved() - ? isGasCostCoveredByBalance() + ? isBalanceGreaterThanGasFees() ? parseFloat(parsedGasCost) : parseFloat(fromValue) : undefined @@ -90,13 +93,13 @@ export const AvailableBalance = ({
Estimated gas: {parseFloat(parsedGasCost).toFixed(4)}
) - } else if (!isGasCostCoveredByInput()) { + } else if (!isInputGreaterThanBalanceMinusGasFees()) { tooltipContent = (
You may not have enough to cover gas fees.
) - } else if (!isGasCostCoveredByBalance()) { + } else if (!isBalanceGreaterThanGasFees()) { tooltipContent = (
Gas fees may exceed your available balance. @@ -121,15 +124,19 @@ export const AvailableBalance = ({ onClick={onMaxBalance} className={labelClassName} > + Gas est: {isTraceInput() ? '<0.001' : gasReserved.toFixed(4)} - reserved for gas + {fromToken?.symbol} ) } else if (hasMounted && isConnected && !disabled) { return (
diff --git a/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx b/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx index 3946e97e9c..bbf371ee63 100644 --- a/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx @@ -147,7 +147,10 @@ export const SwapInputContainer = () => {
{parsedBalance ?? '0.0'} - + )} From a350cf94ab12afc82f173ba9b419c5b5a797c1a6 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Mon, 6 May 2024 22:21:44 -0700 Subject: [PATCH 134/143] Hide MaxButton conditions --- .../components/StateManagedBridge/InputContainer.tsx | 8 +++++--- .../StateManagedSwap/SwapInputContainer.tsx | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 40431b76a8..99190f3800 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -52,7 +52,7 @@ export const InputContainer = () => { const fullParsedBalance = formatBigIntToString(balance, tokenDecimals) const hasValidSelections: boolean = useMemo(() => { - return Boolean(fromChainId && toChainId && fromToken && toToken) + return Boolean(fromChainId && fromToken) }, [fromChainId, toChainId, fromToken, toToken]) const { @@ -145,7 +145,7 @@ export const InputContainer = () => { -
+
{ />
diff --git a/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx b/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx index bbf371ee63..769068b1c8 100644 --- a/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedSwap/SwapInputContainer.tsx @@ -54,10 +54,13 @@ export const SwapInputContainer = () => { ) const parsedBalance = tokenData?.parsedBalance - const balance = tokenData?.balance + const parsedFullBalance = formatBigIntToString( + balance, + tokenData?.token?.decimals[swapChainId] + ) - const isInputMax = parsedBalance === swapFromValue + const isInputMax = parsedFullBalance === swapFromValue useEffect(() => { if ( @@ -136,7 +139,7 @@ export const SwapInputContainer = () => { handleFromValueChange={handleFromValueChange} /> {hasMounted && isConnected && ( -
+
)} From 973fc67369602be2307fee9f26cffd6b3c79ea72 Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 7 May 2024 16:35:31 -0700 Subject: [PATCH 135/143] Show Max when all input selections are made --- .../StateManagedBridge/InputContainer.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx index 99190f3800..a150ed13a4 100644 --- a/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/InputContainer.tsx @@ -51,8 +51,12 @@ export const InputContainer = () => { const parsedBalance = getParsedBalance(balance, tokenDecimals, 4) const fullParsedBalance = formatBigIntToString(balance, tokenDecimals) - const hasValidSelections: boolean = useMemo(() => { + const hasValidFromSelections: boolean = useMemo(() => { return Boolean(fromChainId && fromToken) + }, [fromChainId, fromToken]) + + const hasValidInputSelections: boolean = useMemo(() => { + return Boolean(fromChainId && fromToken && toChainId && toToken) }, [fromChainId, toChainId, fromToken, toToken]) const { @@ -159,12 +163,15 @@ export const InputContainer = () => { onMaxBalance={onMaxBalance} isGasToken={isGasToken} isGasEstimateLoading={isLoading} - isDisabled={!isConnected || !hasValidSelections} + isDisabled={!isConnected || !hasValidFromSelections} />
From 962f37247086990a7652aa69a011d6dd77ff26ff Mon Sep 17 00:00:00 2001 From: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com> Date: Tue, 7 May 2024 16:38:23 -0700 Subject: [PATCH 136/143] Remove click states for AvailableBalance on Bridge/Swap --- .../StateManagedBridge/AvailableBalance.tsx | 14 ++------------ .../StateManagedBridge/InputContainer.tsx | 2 -- .../StateManagedSwap/SwapInputContainer.tsx | 9 ++------- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx index 04c822c698..e3d3a8ebb6 100644 --- a/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/AvailableBalance.tsx @@ -1,8 +1,5 @@ import React from 'react' import { joinClassNames } from '@/utils/joinClassNames' -import { HoverTooltip } from '../HoverTooltip' -import { Token } from '@/utils/types' -import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterDecimal' export const AvailableBalance = ({ balance, @@ -10,7 +7,6 @@ export const AvailableBalance = ({ isGasToken, isGasEstimateLoading, isDisabled, - onMaxBalance, }: { balance?: string maxBridgeableBalance?: number @@ -18,13 +14,11 @@ export const AvailableBalance = ({ isGasToken: boolean isGasEstimateLoading: boolean isDisabled: boolean - onMaxBalance?: () => void }) => { const labelClassName = joinClassNames({ space: 'block', textColor: 'text-xxs md:text-xs', - animation: 'transition-all duration-150 transform-gpu', - hover: 'hover:opacity-70 cursor-pointer', + cursor: 'cursor-default', }) if (isDisabled) { @@ -39,11 +33,7 @@ export const AvailableBalance = ({ ) } else { return ( -