diff --git a/components/ErrorBox.tsx b/components/ErrorBox.tsx index d7a9c1e..3faee3d 100644 --- a/components/ErrorBox.tsx +++ b/components/ErrorBox.tsx @@ -8,7 +8,7 @@ export default function ErrorBox({ heading, children }: { heading: string; child
-
+

{heading}

{children}
diff --git a/config.ts b/config.ts index d3a08e9..9de534c 100644 --- a/config.ts +++ b/config.ts @@ -2,6 +2,10 @@ import { goerli, optimismGoerli } from 'wagmi/chains'; export const chains = [goerli, optimismGoerli]; +declare global { + function isNaN(number: number | string): boolean; +} + export enum DaoId { PoolTogether = 'pool-together', Gitcoin = 'gitcoin', diff --git a/hooks/useEasyWrite.ts b/hooks/useEasyWrite.ts index 3c327b0..00f4c5c 100644 --- a/hooks/useEasyWrite.ts +++ b/hooks/useEasyWrite.ts @@ -17,9 +17,12 @@ export const useEasyWrite = ( data: writeData, error: writeError, isLoading: writeIsLoading, + isSuccess: writeIsSuccess, write: contractWrite, status, } = useContractWrite(config); + console.log('In hook'); + console.log(contractWrite); const { error: waitError, data: transactionData, @@ -37,6 +40,7 @@ export const useEasyWrite = ( isTransactionDataLoading, waitError, }); + console.log('Waitint ended'); useEffect(() => { // The different statuses that we intend to show are: @@ -113,5 +117,7 @@ export const useEasyWrite = ( isTransactionDataLoading, error, write: contractWrite, + isSuccess: writeIsSuccess, + status, }; }; diff --git a/pages/[id]/bridge.tsx b/pages/[id]/bridge.tsx index e5d7515..0cdb7a4 100644 --- a/pages/[id]/bridge.tsx +++ b/pages/[id]/bridge.tsx @@ -1,21 +1,22 @@ import Head from 'next/head'; +import Image from 'next/image'; +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { formatUnits, maxUint256, parseAbi, parseUnits } from 'viem'; +import { useAccount, useContractRead, useNetwork, useWalletClient } from 'wagmi'; + import CardWithHeader from '@/components/CardWithHeader'; import { ExclamationCircleIcon } from '@heroicons/react/20/solid'; import { useHasMounted } from '@/hooks/useHasMounted'; import { useConfig } from '@/hooks/useConfig'; -import { useState } from 'react'; -import { formatUnits, maxUint256, parseAbi, parseUnits } from 'viem'; import { classNames, switchChain } from '@/util'; import { ZERO_ADDRESS } from '@/util/constants'; import { ArrowLongDownIcon } from '@heroicons/react/20/solid'; import { useBalances } from '@/hooks/useBalances'; import { useFees } from '@/hooks/useFees'; -import { useAccount, useContractRead, useNetwork } from 'wagmi'; import { useEasyWrite } from '@/hooks/useEasyWrite'; import ErrorBox from '@/components/ErrorBox'; import Spinner from '@/components/Spinner'; -import { useWalletClient } from 'wagmi'; -import Image from 'next/image'; import { useTokenInfo } from '@/hooks/useTokenInfo'; enum BridgeTarget { @@ -33,6 +34,10 @@ enum ErrorType { type ErrorReturnType = { errorType?: ErrorType; errorReason?: string }; +type FormData = { + amount: string; +}; + const Bridge = () => { const mounted = useHasMounted(); const { fees } = useFees(); @@ -44,9 +49,19 @@ const Bridge = () => { const { chain } = useNetwork(); const { data: walletClient, isLoading: walletIsLoading } = useWalletClient(); + const { + register, + handleSubmit, + formState: { errors, isValid }, + watch, + } = useForm({ mode: 'onChange' }); + // State for amount input - const [amount, setAmount] = useState('0'); - const rawAmount = parseUnits(amount, l1.token?.decimals || 18); + const amount = watch('amount', '0'); + const rawAmount = parseUnits( + Boolean(errors.amount?.message) || isNaN(amount) ? '0' : amount, + l1.token?.decimals || 18 + ); const isNonZeroInput = rawAmount !== BigInt(0); const source = bridgeTarget === BridgeTarget.L2 @@ -105,10 +120,10 @@ const Bridge = () => { const { write: bridgeToL2, isLoading: bridgeToL2IsLoading, + isSuccess, error: bridgeToL2Error, } = useEasyWrite({ enabled: - isNonZeroInput && bridgeTarget === BridgeTarget.L2 && !needsAllowanceL1 && !approveL1IsLoading && @@ -123,6 +138,12 @@ const Bridge = () => { value: fees?.l1 || BigInt(0), isCrossChain: true, }); + console.log('Nrp'); + console.log(bridgeToL2); + console.log(bridgeToL2IsLoading); + console.log(isSuccess); + console.log(amount); + console.log(isValid); // 2️⃣ l2 bridge to l1 const { @@ -130,7 +151,7 @@ const Bridge = () => { isLoading: bridgeToL1IsLoading, error: bridgeToL1Error, } = useEasyWrite({ - enabled: isNonZeroInput && bridgeTarget === BridgeTarget.L1 && source.chain.id === chain?.id, + enabled: bridgeTarget === BridgeTarget.L1 && source.chain.id === chain?.id, address: l2Config.tokenAddress, chainId: l2Config.chain.id, abi: parseAbi(['function l1Unlock(address to, uint256 amount) public payable']), @@ -144,10 +165,6 @@ const Bridge = () => { setBridgeTarget(bridgeTarget === BridgeTarget.L2 ? BridgeTarget.L1 : BridgeTarget.L2); }; - const handleInputChange = (e: React.FormEvent) => { - setAmount(e.currentTarget.value); - }; - const handleAllowance = () => { if (!approveL1) return; approveL1(); @@ -155,6 +172,8 @@ const Bridge = () => { const handleBridge = () => { if (bridgeTarget === BridgeTarget.L2) { + console.log('Handle'); + console.log(bridgeToL2); if (!bridgeToL2) throw new Error('bridgeToL2 is not defined'); bridgeToL2(); } else { @@ -163,6 +182,10 @@ const Bridge = () => { } }; + const onSubmit = handleSubmit(async () => { + handleBridge(); + }); + const formatError = (e: Error | null): ErrorReturnType => { if (!isSufficientBalance) { return { @@ -204,7 +227,8 @@ const Bridge = () => { e.message?.includes(errorSearchString) ); if (!foundError) { - return { errorType: ErrorType.Unknown, errorReason: `Can't parse error.\n\n${e.message}.` }; + console.error(e.message); + return { errorType: ErrorType.Unknown, errorReason: `Error cannot be parsed` }; } return { errorType: foundError.errorType, errorReason: foundError.prettyReason }; }; @@ -217,7 +241,6 @@ const Bridge = () => { const { errorType, errorReason } = formatError(error); // Helpers for different parts of UI state const isAmountError = errorType === ErrorType.ERC20AmountError; - const isEthError = errorType === ErrorType.InsufficientNativeCurrencyError; return ( <> @@ -261,37 +284,48 @@ const Bridge = () => { />
{/* Bottom row: Input form */} -
+
{ + // isNan coerces to a number + if (isNaN(value)) { + return 'Amount needs to be a number'; + } + if (parseFloat(value) <= 0) { + return 'Amount must be positive'; + } + return true; + }, + })} />
+ {mounted && errors?.amount && ( +

{errors.amount.message}

+ )} +

{ mounted && ( /* ⚪️ Finally, we can show the bridge button. */

- +