diff --git a/.changeset/tasty-ties-bow.md b/.changeset/tasty-ties-bow.md new file mode 100644 index 000000000..6241fac41 --- /dev/null +++ b/.changeset/tasty-ties-bow.md @@ -0,0 +1,11 @@ +--- +"create-eth": patch +--- + +- revert #875 (https://github.com/scaffold-eth/scaffold-eth-2/pull/905) +- Fix typos (https://github.com/scaffold-eth/scaffold-eth-2/pull/906) +- Exclude external links from triggering progress bar ([#909](https://github.com/scaffold-eth/scaffold-eth-2/pull/909)) +- Handle tx revert in `useTransactor` (https://github.com/scaffold-eth/scaffold-eth-2/pull/907) +- show blockexplorer link when transaction is reverted (https://github.com/scaffold-eth/scaffold-eth-2/pull/910) +- fix: useScaffoldEventHistory caching (https://github.com/scaffold-eth/scaffold-eth-2/pull/916) +- allow json module imports (https://github.com/scaffold-eth/scaffold-eth-2/pull/921) diff --git a/templates/base/packages/nextjs/app/debug/_components/contract/Tuple.tsx b/templates/base/packages/nextjs/app/debug/_components/contract/Tuple.tsx index 0e3175db0..7ec7e7ec0 100644 --- a/templates/base/packages/nextjs/app/debug/_components/contract/Tuple.tsx +++ b/templates/base/packages/nextjs/app/debug/_components/contract/Tuple.tsx @@ -1,6 +1,6 @@ import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { ContractInput } from "./ContractInput"; -import { getFunctionInputKey, getInitalTupleFormState } from "./utilsContract"; +import { getFunctionInputKey, getInitialTupleFormState } from "./utilsContract"; import { replacer } from "~~/utils/scaffold-eth/common"; import { AbiParameterTuple } from "~~/utils/scaffold-eth/contract"; @@ -12,7 +12,7 @@ type TupleProps = { }; export const Tuple = ({ abiTupleParameter, setParentForm, parentStateObjectKey }: TupleProps) => { - const [form, setForm] = useState>(() => getInitalTupleFormState(abiTupleParameter)); + const [form, setForm] = useState>(() => getInitialTupleFormState(abiTupleParameter)); useEffect(() => { const values = Object.values(form); diff --git a/templates/base/packages/nextjs/app/debug/_components/contract/TupleArray.tsx b/templates/base/packages/nextjs/app/debug/_components/contract/TupleArray.tsx index 1eb23c258..b5992116b 100644 --- a/templates/base/packages/nextjs/app/debug/_components/contract/TupleArray.tsx +++ b/templates/base/packages/nextjs/app/debug/_components/contract/TupleArray.tsx @@ -1,6 +1,6 @@ import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { ContractInput } from "./ContractInput"; -import { getFunctionInputKey, getInitalTupleArrayFormState } from "./utilsContract"; +import { getFunctionInputKey, getInitialTupleArrayFormState } from "./utilsContract"; import { replacer } from "~~/utils/scaffold-eth/common"; import { AbiParameterTuple } from "~~/utils/scaffold-eth/contract"; @@ -12,7 +12,7 @@ type TupleArrayProps = { }; export const TupleArray = ({ abiTupleParameter, setParentForm, parentStateObjectKey }: TupleArrayProps) => { - const [form, setForm] = useState>(() => getInitalTupleArrayFormState(abiTupleParameter)); + const [form, setForm] = useState>(() => getInitialTupleArrayFormState(abiTupleParameter)); const [additionalInputs, setAdditionalInputs] = useState>([ abiTupleParameter.components, ]); diff --git a/templates/base/packages/nextjs/app/debug/_components/contract/utilsContract.tsx b/templates/base/packages/nextjs/app/debug/_components/contract/utilsContract.tsx index 217012ce3..55ef9a4f6 100644 --- a/templates/base/packages/nextjs/app/debug/_components/contract/utilsContract.tsx +++ b/templates/base/packages/nextjs/app/debug/_components/contract/utilsContract.tsx @@ -86,7 +86,7 @@ const getInitialFormState = (abiFunction: AbiFunction) => { return initialForm; }; -const getInitalTupleFormState = (abiTupleParameter: AbiParameterTuple) => { +const getInitialTupleFormState = (abiTupleParameter: AbiParameterTuple) => { const initialForm: Record = {}; if (abiTupleParameter.components.length === 0) return initialForm; @@ -97,7 +97,7 @@ const getInitalTupleFormState = (abiTupleParameter: AbiParameterTuple) => { return initialForm; }; -const getInitalTupleArrayFormState = (abiTupleParameter: AbiParameterTuple) => { +const getInitialTupleArrayFormState = (abiTupleParameter: AbiParameterTuple) => { const initialForm: Record = {}; if (abiTupleParameter.components.length === 0) return initialForm; abiTupleParameter.components.forEach((component, componentIndex) => { @@ -158,7 +158,7 @@ export { getFunctionInputKey, getInitialFormState, getParsedContractFunctionArgs, - getInitalTupleFormState, - getInitalTupleArrayFormState, + getInitialTupleFormState, + getInitialTupleArrayFormState, transformAbiFunction, }; diff --git a/templates/base/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx b/templates/base/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx index c6fa24b50..b9ce162ff 100644 --- a/templates/base/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +++ b/templates/base/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx @@ -48,7 +48,7 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C }, }); - const { data: ensAvatar, isLoading: isEnsAvtarLoading } = useEnsAvatar({ + const { data: ensAvatar, isLoading: isEnsAvatarLoading } = useEnsAvatar({ name: ensName ? normalize(ensName) : undefined, chainId: 1, query: { @@ -94,7 +94,7 @@ export const AddressInput = ({ value, name, placeholder, onChange, disabled }: C prefix={ ensName ? (
- {isEnsAvtarLoading &&
} + {isEnsAvatarLoading &&
} {ensAvatar ? ( { diff --git a/templates/base/packages/nextjs/components/scaffold-eth/ProgressBar.tsx b/templates/base/packages/nextjs/components/scaffold-eth/ProgressBar.tsx index 9ade9bc35..001f787a3 100644 --- a/templates/base/packages/nextjs/components/scaffold-eth/ProgressBar.tsx +++ b/templates/base/packages/nextjs/components/scaffold-eth/ProgressBar.tsx @@ -45,11 +45,12 @@ export function ProgressBar() { NProgress.configure({ showSpinner: false }); const handleAnchorClick = (event: MouseEvent) => { - const targetUrl = (event.currentTarget as HTMLAnchorElement).href; + const anchor = event.currentTarget as HTMLAnchorElement; + const targetUrl = anchor.href; const currentUrl = location.href; - if (targetUrl !== currentUrl) { - NProgress.start(); - } + const isTargetBlank = anchor?.target === "_blank"; + if (targetUrl === currentUrl || isTargetBlank) return; + NProgress.start(); }; const handleMutation: MutationCallback = () => { diff --git a/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts b/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts index 48f8ed671..2477a9b20 100644 --- a/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts +++ b/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts @@ -5,6 +5,7 @@ import { Abi, AbiEvent, ExtractAbiEventNames } from "abitype"; import { BlockNumber, GetLogsParameters } from "viem"; import { Config, UsePublicClientReturnType, useBlockNumber, usePublicClient } from "wagmi"; import { useDeployedContractInfo } from "~~/hooks/scaffold-eth"; +import { replacer } from "~~/utils/scaffold-eth/common"; import { ContractAbi, ContractName, @@ -105,6 +106,7 @@ export const useScaffoldEventHistory = < eventName, fromBlock: fromBlock.toString(), chainId: targetNetwork.id, + filters: JSON.stringify(filters, replacer), }, ], queryFn: async ({ pageParam }) => { diff --git a/templates/base/packages/nextjs/hooks/scaffold-eth/useTransactor.tsx b/templates/base/packages/nextjs/hooks/scaffold-eth/useTransactor.tsx index 0d14e1420..fe21cd2b9 100644 --- a/templates/base/packages/nextjs/hooks/scaffold-eth/useTransactor.tsx +++ b/templates/base/packages/nextjs/hooks/scaffold-eth/useTransactor.tsx @@ -1,5 +1,5 @@ import { getPublicClient } from "@wagmi/core"; -import { Hash, SendTransactionParameters, WalletClient } from "viem"; +import { Hash, SendTransactionParameters, TransactionReceipt, WalletClient } from "viem"; import { Config, useWalletClient } from "wagmi"; import { SendTransactionMutate } from "wagmi/query"; import { wagmiConfig } from "~~/services/web3/wagmiConfig"; @@ -48,6 +48,8 @@ export const useTransactor = (_walletClient?: WalletClient): TransactionFunc => let notificationId = null; let transactionHash: Hash | undefined = undefined; + let transactionReceipt: TransactionReceipt | undefined; + let blockExplorerTxURL = ""; try { const network = await walletClient.getChainId(); // Get full transaction from public client @@ -65,18 +67,20 @@ export const useTransactor = (_walletClient?: WalletClient): TransactionFunc => } notification.remove(notificationId); - const blockExplorerTxURL = network ? getBlockExplorerTxLink(network, transactionHash) : ""; + blockExplorerTxURL = network ? getBlockExplorerTxLink(network, transactionHash) : ""; notificationId = notification.loading( , ); - const transactionReceipt = await publicClient.waitForTransactionReceipt({ + transactionReceipt = await publicClient.waitForTransactionReceipt({ hash: transactionHash, confirmations: options?.blockConfirmations, }); notification.remove(notificationId); + if (transactionReceipt.status === "reverted") throw new Error("Transaction reverted"); + notification.success( , { @@ -91,6 +95,13 @@ export const useTransactor = (_walletClient?: WalletClient): TransactionFunc => } console.error("⚡️ ~ file: useTransactor.ts ~ error", error); const message = getParsedError(error); + + // if receipt was reverted, show notification with block explorer link and return error + if (transactionReceipt?.status === "reverted") { + notification.error(); + throw error; + } + notification.error(message); throw error; } diff --git a/templates/base/packages/nextjs/utils/scaffold-eth/contract.ts b/templates/base/packages/nextjs/utils/scaffold-eth/contract.ts index bf4580d1a..24e84b5e5 100644 --- a/templates/base/packages/nextjs/utils/scaffold-eth/contract.ts +++ b/templates/base/packages/nextjs/utils/scaffold-eth/contract.ts @@ -131,13 +131,13 @@ export type WriteAbiStateMutability = "nonpayable" | "payable"; export type FunctionNamesWithInputs< TContractName extends ContractName, - TAbiStateMutibility extends AbiStateMutability = AbiStateMutability, + TAbiStateMutability extends AbiStateMutability = AbiStateMutability, > = Exclude< Extract< ContractAbi[number], { type: "function"; - stateMutability: TAbiStateMutibility; + stateMutability: TAbiStateMutability; } >, { @@ -149,14 +149,14 @@ type Expand = T extends object ? (T extends infer O ? { [K in keyof O]: O[K] type UnionToIntersection = Expand<(U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never>; -type OptionalTupple = T extends readonly [infer H, ...infer R] ? readonly [H | undefined, ...OptionalTupple] : T; +type OptionalTuple = T extends readonly [infer H, ...infer R] ? readonly [H | undefined, ...OptionalTuple] : T; type UseScaffoldArgsParam< TContractName extends ContractName, TFunctionName extends ExtractAbiFunctionNames>, > = TFunctionName extends FunctionNamesWithInputs ? { - args: OptionalTupple, TFunctionName>>>; + args: OptionalTuple, TFunctionName>>>; value?: ExtractAbiFunction, TFunctionName>["stateMutability"] extends "payable" ? bigint | undefined : undefined; diff --git a/templates/solidity-frameworks/hardhat/packages/hardhat/tsconfig.json b/templates/solidity-frameworks/hardhat/packages/hardhat/tsconfig.json index e5f1a6400..2ea087e4a 100644 --- a/templates/solidity-frameworks/hardhat/packages/hardhat/tsconfig.json +++ b/templates/solidity-frameworks/hardhat/packages/hardhat/tsconfig.json @@ -3,6 +3,7 @@ "target": "es2020", "module": "commonjs", "esModuleInterop": true, + "resolveJsonModule": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true