Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional chain parameter in Scaffold hooks #931

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions packages/nextjs/hooks/scaffold-eth/useDeployedContractInfo.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import { useEffect, useState } from "react";
import { useTargetNetwork } from "./useTargetNetwork";
import { useIsMounted } from "usehooks-ts";
import { Chain } from "viem";
import { usePublicClient } from "wagmi";
import { Contract, ContractCodeStatus, ContractName, contracts } from "~~/utils/scaffold-eth/contract";

/**
* Gets the matching contract info for the provided contract name from the contracts present in deployedContracts.ts
* and externalContracts.ts corresponding to targetNetworks configured in scaffold.config.ts
*/
export const useDeployedContractInfo = <TContractName extends ContractName>(contractName: TContractName) => {
export const useDeployedContractInfo = <TContractName extends ContractName>(
contractName: TContractName,
chain?: Chain,
) => {
const isMounted = useIsMounted();
const { targetNetwork } = useTargetNetwork();
const deployedContract = contracts?.[targetNetwork.id]?.[contractName as ContractName] as Contract<TContractName>;
const selectedChain = chain ?? targetNetwork;

const deployedContract = contracts?.[selectedChain.id]?.[contractName as ContractName] as Contract<TContractName>;
const [status, setStatus] = useState<ContractCodeStatus>(ContractCodeStatus.LOADING);
const publicClient = usePublicClient({ chainId: targetNetwork.id });
const publicClient = usePublicClient({ chainId: selectedChain.id });

useEffect(() => {
const checkContractDeployment = async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/nextjs/hooks/scaffold-eth/useNetworkColor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ export function getNetworkColor(network: ChainWithAttributes, isDarkMode: boolea
/**
* Gets the color of the target network
*/
export const useNetworkColor = () => {
export const useNetworkColor = (chain?: ChainWithAttributes) => {
const { resolvedTheme } = useTheme();
const { targetNetwork } = useTargetNetwork();

const isDarkMode = resolvedTheme === "dark";

return getNetworkColor(targetNetwork, isDarkMode);
return getNetworkColor(chain ? chain : targetNetwork, isDarkMode);
};
12 changes: 10 additions & 2 deletions packages/nextjs/hooks/scaffold-eth/useScaffoldContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,21 @@ export const useScaffoldContract = <
>({
contractName,
walletClient,
chain,
}: {
contractName: TContractName;
walletClient?: TWalletClient | null;
chain?: Chain;
}) => {
const { data: deployedContractData, isLoading: deployedContractLoading } = useDeployedContractInfo(contractName);
const { targetNetwork } = useTargetNetwork();
const publicClient = usePublicClient({ chainId: targetNetwork.id });
const selectedChain = chain ?? targetNetwork;

const { data: deployedContractData, isLoading: deployedContractLoading } = useDeployedContractInfo(
contractName,
selectedChain,
);

const publicClient = usePublicClient({ chainId: selectedChain?.id });

let contract = undefined;
if (deployedContractData && publicClient) {
Expand Down
11 changes: 7 additions & 4 deletions packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const useScaffoldEventHistory = <
contractName,
eventName,
fromBlock,
chain,
filters,
blockData,
transactionData,
Expand All @@ -82,14 +83,16 @@ export const useScaffoldEventHistory = <
enabled = true,
}: UseScaffoldEventHistoryConfig<TContractName, TEventName, TBlockData, TTransactionData, TReceiptData>) => {
const { targetNetwork } = useTargetNetwork();
const selectedChain = chain ?? targetNetwork;

const publicClient = usePublicClient({
chainId: targetNetwork.id,
chainId: selectedChain.id,
});
const [isFirstRender, setIsFirstRender] = useState(true);

const { data: blockNumber } = useBlockNumber({ watch: watch, chainId: targetNetwork.id });
const { data: blockNumber } = useBlockNumber({ watch: watch, chainId: selectedChain.id });

const { data: deployedContractData } = useDeployedContractInfo(contractName);
const { data: deployedContractData } = useDeployedContractInfo(contractName, selectedChain);

const event =
deployedContractData &&
Expand All @@ -105,7 +108,7 @@ export const useScaffoldEventHistory = <
address: deployedContractData?.address,
eventName,
fromBlock: fromBlock.toString(),
chainId: targetNetwork.id,
chainId: selectedChain.id,
filters: JSON.stringify(filters, replacer),
},
],
Expand Down
9 changes: 6 additions & 3 deletions packages/nextjs/hooks/scaffold-eth/useScaffoldReadContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,19 @@ export const useScaffoldReadContract = <
contractName,
functionName,
args,
chain,
...readConfig
}: UseScaffoldReadConfig<TContractName, TFunctionName>) => {
const { data: deployedContract } = useDeployedContractInfo(contractName);
const { targetNetwork } = useTargetNetwork();
const selectedChain = chain ?? targetNetwork;
const { data: deployedContract } = useDeployedContractInfo(contractName, selectedChain);

const { query: queryOptions, watch, ...readContractConfig } = readConfig;
// set watch to true by default
const defaultWatch = watch ?? true;

const readContractHookRes = useReadContract({
chainId: targetNetwork.id,
chainId: selectedChain.id,
functionName,
address: deployedContract?.address,
abi: deployedContract?.abi,
Expand All @@ -56,7 +59,7 @@ export const useScaffoldReadContract = <
const queryClient = useQueryClient();
const { data: blockNumber } = useBlockNumber({
watch: defaultWatch,
chainId: targetNetwork.id,
chainId: selectedChain.id,
query: {
enabled: defaultWatch,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ export const useScaffoldWatchContractEvent = <
>({
contractName,
eventName,
chain,
onLogs,
}: UseScaffoldEventConfig<TContractName, TEventName>) => {
const { data: deployedContractData } = useDeployedContractInfo(contractName);
const { targetNetwork } = useTargetNetwork();
const selectedChain = chain ?? targetNetwork;
const { data: deployedContractData } = useDeployedContractInfo(contractName, selectedChain);

const addIndexedArgsToLogs = (logs: Log[]) => logs.map(addIndexedArgsToEvent);
const listenerWithIndexedArgs = (logs: Log[]) => onLogs(addIndexedArgsToLogs(logs) as Parameters<typeof onLogs>[0]);

return useWatchContractEvent({
address: deployedContractData?.address,
abi: deployedContractData?.abi as Abi,
chainId: targetNetwork.id,
chainId: selectedChain.id,
onLogs: listenerWithIndexedArgs,
eventName,
});
Expand Down
22 changes: 14 additions & 8 deletions packages/nextjs/hooks/scaffold-eth/useScaffoldWriteContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from "react";
import { useTargetNetwork } from "./useTargetNetwork";
import { MutateOptions } from "@tanstack/react-query";
import { Abi, ExtractAbiFunctionNames } from "abitype";
import { Chain } from "viem";
import { Config, UseWriteContractParameters, useAccount, useWriteContract } from "wagmi";
import { WriteContractErrorType, WriteContractReturnType } from "wagmi/actions";
import { WriteContractVariables } from "wagmi/query";
Expand All @@ -22,16 +23,19 @@ import {
*/
export const useScaffoldWriteContract = <TContractName extends ContractName>(
contractName: TContractName,
chain?: Chain,
Copy link
Member

@rin-st rin-st Sep 9, 2024

Choose a reason for hiding this comment

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

Thank you for pr @Hotmanics !

Some thoughts regarding params:
so if I want for example pass writeContractParams without chain, I need to use undefined every time?

const { writeContractAsync } = useScaffoldWriteContract("YourContract", undefined, {});

changing order to contractName, writeContractParams?, chain? will cause same problem when needed to pass chain without writeContractParams.

So maybe we need to change params to object {contractName, writeContractParams?, chain?} here and for all other hooks without object in params? And params will become more consistent. Because for now somewhere we have objects, somewhere not. Or another option: (contractName, options?: {writeContractParams?, chain?}) but I'm voting for one object. Probably this can be changed in later pr's

Don't change it right now, let's wait Shiv or Carlos

cc @technophile-04 @carletex

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are absolutely correct. This was an oversight by me.

Not sure as the best path forward, I'm sure others will be able to provide a more detailed observation.

Appreciate you looking at the PR!

writeContractParams?: UseWriteContractParameters,
) => {
const { chain } = useAccount();
const { chain: accountChain } = useAccount();
const writeTx = useTransactor();
const [isMining, setIsMining] = useState(false);
const { targetNetwork } = useTargetNetwork();

const wagmiContractWrite = useWriteContract(writeContractParams);

const { data: deployedContractData } = useDeployedContractInfo(contractName);
const selectedNetwork = chain ?? targetNetwork;

const { data: deployedContractData } = useDeployedContractInfo(contractName, selectedNetwork);

const sendContractWriteAsyncTx = async <
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, "nonpayable" | "payable">,
Expand All @@ -44,12 +48,13 @@ export const useScaffoldWriteContract = <TContractName extends ContractName>(
return;
}

if (!chain?.id) {
if (!accountChain?.id) {
notification.error("Please connect your wallet");
return;
}
if (chain?.id !== targetNetwork.id) {
notification.error("You are on the wrong network");

if (accountChain?.id !== selectedNetwork.id) {
notification.error("Your wallet is connected to the wrong network");
return;
}

Expand Down Expand Up @@ -93,12 +98,13 @@ export const useScaffoldWriteContract = <TContractName extends ContractName>(
notification.error("Target Contract is not deployed, did you forget to run `yarn deploy`?");
return;
}
if (!chain?.id) {
if (!accountChain?.id) {
notification.error("Please connect your wallet");
return;
}
if (chain?.id !== targetNetwork.id) {
notification.error("You are on the wrong network");

if (accountChain?.id !== selectedNetwork.id) {
notification.error("Your wallet is connected to the wrong network");
return;
}

Expand Down
4 changes: 4 additions & 0 deletions packages/nextjs/utils/scaffold-eth/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { MergeDeepRecord } from "type-fest/source/merge-deep";
import {
Address,
Block,
Chain,
GetEventArgs,
GetTransactionReceiptReturnType,
GetTransactionReturnType,
Expand Down Expand Up @@ -170,6 +171,7 @@ export type UseScaffoldReadConfig<
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, ReadAbiStateMutability>,
> = {
contractName: TContractName;
chain?: Chain;
watch?: boolean;
} & IsContractDeclarationMissing<
Partial<UseReadContractParameters>,
Expand Down Expand Up @@ -215,6 +217,7 @@ export type UseScaffoldEventConfig<
> = {
contractName: TContractName;
eventName: TEventName;
chain?: Chain;
} & IsContractDeclarationMissing<
Omit<UseWatchContractEventParameters, "onLogs" | "address" | "abi" | "eventName"> & {
onLogs: (
Expand Down Expand Up @@ -274,6 +277,7 @@ export type UseScaffoldEventHistoryConfig<
contractName: TContractName;
eventName: IsContractDeclarationMissing<string, TEventName>;
fromBlock: bigint;
chain?: Chain;
filters?: EventFilters<TContractName, TEventName>;
blockData?: TBlockData;
transactionData?: TTransactionData;
Expand Down
Loading