Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/upstream-main' into backmerge-16…
Browse files Browse the repository at this point in the history
…-12-24
  • Loading branch information
technophile-04 committed Dec 16, 2024
2 parents 8e53d38 + 2a32e1a commit 6a72141
Show file tree
Hide file tree
Showing 17 changed files with 203 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type ContractUIProps = {
export const ContractUI = ({ contractName, className = "" }: ContractUIProps) => {
const [refreshDisplayVariables, triggerRefreshDisplayVariables] = useReducer(value => !value, false);
const { targetNetwork } = useTargetNetwork();
const { data: deployedContractData, isLoading: deployedContractLoading } = useDeployedContractInfo(contractName);
const { data: deployedContractData, isLoading: deployedContractLoading } = useDeployedContractInfo({ contractName });
const networkColor = useNetworkColor();

if (deployedContractLoading) {
Expand Down
1 change: 1 addition & 0 deletions templates/base/packages/nextjs/hooks/scaffold-eth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from "./useScaffoldWriteContract";
export * from "./useTargetNetwork";
export * from "./useTransactor";
export * from "./useWatchBalance";
export * from "./useSelectedNetwork";
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import { useEffect, useState } from "react";
import { useTargetNetwork } from "./useTargetNetwork";
import { useIsMounted } from "usehooks-ts";
import { usePublicClient } from "wagmi";
import { Contract, ContractCodeStatus, ContractName, contracts } from "~~/utils/scaffold-eth/contract";
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
import {
Contract,
ContractCodeStatus,
ContractName,
UseDeployedContractConfig,
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,
chainId,
}: UseDeployedContractConfig<TContractName>) => {
const isMounted = useIsMounted();
const { targetNetwork } = useTargetNetwork();
const deployedContract = contracts?.[targetNetwork.id]?.[contractName as ContractName] as Contract<TContractName>;

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

useEffect(() => {
const checkContractDeployment = async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useTargetNetwork } from "./useTargetNetwork";
import { useTheme } from "next-themes";
import { ChainWithAttributes } from "~~/utils/scaffold-eth";
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
import { AllowedChainIds, ChainWithAttributes } from "~~/utils/scaffold-eth";

export const DEFAULT_NETWORK_COLOR: [string, string] = ["#666666", "#bbbbbb"];

Expand All @@ -12,11 +13,11 @@ export function getNetworkColor(network: ChainWithAttributes, isDarkMode: boolea
/**
* Gets the color of the target network
*/
export const useNetworkColor = () => {
export const useNetworkColor = (chainId?: AllowedChainIds) => {
const { resolvedTheme } = useTheme();
const { targetNetwork } = useTargetNetwork();

const chain = useSelectedNetwork(chainId);
const isDarkMode = resolvedTheme === "dark";

return getNetworkColor(targetNetwork, isDarkMode);
return getNetworkColor(chain, isDarkMode);
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useTargetNetwork } from "./useTargetNetwork";
import { Account, Address, Chain, Client, Transport, getContract } from "viem";
import { usePublicClient } from "wagmi";
import { GetWalletClientReturnType } from "wagmi/actions";
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
import { AllowedChainIds } from "~~/utils/scaffold-eth";
import { Contract, ContractName } from "~~/utils/scaffold-eth/contract";

/**
Expand All @@ -11,20 +12,27 @@ import { Contract, ContractName } from "~~/utils/scaffold-eth/contract";
* @param config - The config settings for the hook
* @param config.contractName - deployed contract name
* @param config.walletClient - optional walletClient from wagmi useWalletClient hook can be passed for doing write transactions
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
*/
export const useScaffoldContract = <
TContractName extends ContractName,
TWalletClient extends Exclude<GetWalletClientReturnType, null> | undefined,
>({
contractName,
walletClient,
chainId,
}: {
contractName: TContractName;
walletClient?: TWalletClient | null;
chainId?: AllowedChainIds;
}) => {
const { data: deployedContractData, isLoading: deployedContractLoading } = useDeployedContractInfo(contractName);
const { targetNetwork } = useTargetNetwork();
const publicClient = usePublicClient({ chainId: targetNetwork.id });
const selectedNetwork = useSelectedNetwork(chainId);
const { data: deployedContractData, isLoading: deployedContractLoading } = useDeployedContractInfo({
contractName,
chainId: selectedNetwork?.id as AllowedChainIds,
});

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

let contract = undefined;
if (deployedContractData && publicClient) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useEffect, useState } from "react";
import { useTargetNetwork } from "./useTargetNetwork";
import { useInfiniteQuery } from "@tanstack/react-query";
import { Abi, AbiEvent, ExtractAbiEventNames } from "abitype";
import { BlockNumber, GetLogsParameters } from "viem";
import { Config, UsePublicClientReturnType, useBlockNumber, usePublicClient } from "wagmi";
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
import { AllowedChainIds } from "~~/utils/scaffold-eth";
import { replacer } from "~~/utils/scaffold-eth/common";
import {
ContractAbi,
Expand Down Expand Up @@ -57,6 +58,7 @@ const getEvents = async (
* @param config.contractName - deployed contract name
* @param config.eventName - name of the event to listen for
* @param config.fromBlock - the block number to start reading events from
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
* @param config.filters - filters to be applied to the event (parameterName: value)
* @param config.blockData - if set to true it will return the block data for each event (default: false)
* @param config.transactionData - if set to true it will return the transaction data for each event (default: false)
Expand All @@ -74,22 +76,27 @@ export const useScaffoldEventHistory = <
contractName,
eventName,
fromBlock,
chainId,
filters,
blockData,
transactionData,
receiptData,
watch,
enabled = true,
}: UseScaffoldEventHistoryConfig<TContractName, TEventName, TBlockData, TTransactionData, TReceiptData>) => {
const { targetNetwork } = useTargetNetwork();
const selectedNetwork = useSelectedNetwork(chainId);

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

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

const { data: deployedContractData } = useDeployedContractInfo(contractName);
const { data: deployedContractData } = useDeployedContractInfo({
contractName,
chainId: selectedNetwork.id as AllowedChainIds,
});

const event =
deployedContractData &&
Expand All @@ -105,7 +112,7 @@ export const useScaffoldEventHistory = <
address: deployedContractData?.address,
eventName,
fromBlock: fromBlock.toString(),
chainId: targetNetwork.id,
chainId: selectedNetwork.id,
filters: JSON.stringify(filters, replacer),
},
],
Expand All @@ -121,8 +128,18 @@ export const useScaffoldEventHistory = <
},
enabled: enabled && isContractAddressAndClientReady,
initialPageParam: fromBlock,
getNextPageParam: () => {
return blockNumber;
getNextPageParam: (lastPage, allPages, lastPageParam) => {
if (!blockNumber || fromBlock >= blockNumber) return undefined;

const lastPageHighestBlock = Math.max(
Number(fromBlock),
...(lastPage || []).map(event => Number(event.blockNumber || 0)),
);
const nextBlock = BigInt(Math.max(Number(lastPageParam), lastPageHighestBlock) + 1);

if (nextBlock > blockNumber) return undefined;

return nextBlock;
},
select: data => {
const events = data.pages.flat();
Expand All @@ -133,6 +150,7 @@ export const useScaffoldEventHistory = <
TTransactionData,
TReceiptData
>;

return {
pages: eventHistoryData?.reverse(),
pageParams: data.pageParams,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useEffect } from "react";
import { useTargetNetwork } from "./useTargetNetwork";
import { QueryObserverResult, RefetchOptions, useQueryClient } from "@tanstack/react-query";
import type { ExtractAbiFunctionNames } from "abitype";
import { ReadContractErrorType } from "viem";
import { useBlockNumber, useReadContract } from "wagmi";
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
import { AllowedChainIds } from "~~/utils/scaffold-eth";
import {
AbiFunctionReturnType,
ContractAbi,
Expand All @@ -19,6 +20,7 @@ import {
* @param config.contractName - deployed contract name
* @param config.functionName - name of the function to be called
* @param config.args - args to be passed to the function call
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
*/
export const useScaffoldReadContract = <
TContractName extends ContractName,
Expand All @@ -27,16 +29,21 @@ export const useScaffoldReadContract = <
contractName,
functionName,
args,
chainId,
...readConfig
}: UseScaffoldReadConfig<TContractName, TFunctionName>) => {
const { data: deployedContract } = useDeployedContractInfo(contractName);
const { targetNetwork } = useTargetNetwork();
const selectedNetwork = useSelectedNetwork(chainId);
const { data: deployedContract } = useDeployedContractInfo({
contractName,
chainId: selectedNetwork.id as AllowedChainIds,
});

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

const readContractHookRes = useReadContract({
chainId: targetNetwork.id,
chainId: selectedNetwork.id,
functionName,
address: deployedContract?.address,
abi: deployedContract?.abi,
Expand All @@ -56,7 +63,7 @@ export const useScaffoldReadContract = <
const queryClient = useQueryClient();
const { data: blockNumber } = useBlockNumber({
watch: defaultWatch,
chainId: targetNetwork.id,
chainId: selectedNetwork.id,
query: {
enabled: defaultWatch,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useTargetNetwork } from "./useTargetNetwork";
import { Abi, ExtractAbiEventNames } from "abitype";
import { Log } from "viem";
import { useWatchContractEvent } from "wagmi";
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
import { addIndexedArgsToEvent, useDeployedContractInfo } from "~~/hooks/scaffold-eth";
import { AllowedChainIds } from "~~/utils/scaffold-eth";
import { ContractAbi, ContractName, UseScaffoldEventConfig } from "~~/utils/scaffold-eth/contract";

/**
Expand All @@ -11,6 +12,7 @@ import { ContractAbi, ContractName, UseScaffoldEventConfig } from "~~/utils/scaf
* @param config - The config settings
* @param config.contractName - deployed contract name
* @param config.eventName - name of the event to listen for
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
* @param config.onLogs - the callback that receives events.
*/
export const useScaffoldWatchContractEvent = <
Expand All @@ -19,18 +21,22 @@ export const useScaffoldWatchContractEvent = <
>({
contractName,
eventName,
chainId,
onLogs,
}: UseScaffoldEventConfig<TContractName, TEventName>) => {
const { data: deployedContractData } = useDeployedContractInfo(contractName);
const { targetNetwork } = useTargetNetwork();
const selectedNetwork = useSelectedNetwork(chainId);
const { data: deployedContractData } = useDeployedContractInfo({
contractName,
chainId: selectedNetwork.id as AllowedChainIds,
});

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: selectedNetwork.id,
onLogs: listenerWithIndexedArgs,
eventName,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,44 @@
import { useState } from "react";
import { useTargetNetwork } from "./useTargetNetwork";
import { MutateOptions } from "@tanstack/react-query";
import { Abi, ExtractAbiFunctionNames } from "abitype";
import { Config, UseWriteContractParameters, useAccount, useWriteContract } from "wagmi";
import { Config, useAccount, useWriteContract } from "wagmi";
import { WriteContractErrorType, WriteContractReturnType } from "wagmi/actions";
import { WriteContractVariables } from "wagmi/query";
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
import { useDeployedContractInfo, useTransactor } from "~~/hooks/scaffold-eth";
import { notification } from "~~/utils/scaffold-eth";
import { AllowedChainIds, notification } from "~~/utils/scaffold-eth";
import {
ContractAbi,
ContractName,
ScaffoldWriteContractOptions,
ScaffoldWriteContractVariables,
UseScaffoldWriteConfig,
} from "~~/utils/scaffold-eth/contract";

/**
* Wrapper around wagmi's useWriteContract hook which automatically loads (by name) the contract ABI and address from
* the contracts present in deployedContracts.ts & externalContracts.ts corresponding to targetNetworks configured in scaffold.config.ts
* @param contractName - name of the contract to be written to
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
* @param writeContractParams - wagmi's useWriteContract parameters
*/
export const useScaffoldWriteContract = <TContractName extends ContractName>(
contractName: TContractName,
writeContractParams?: UseWriteContractParameters,
) => {
const { chain } = useAccount();
export const useScaffoldWriteContract = <TContractName extends ContractName>({
contractName,
chainId,
writeContractParams,
}: UseScaffoldWriteConfig<TContractName>) => {
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 = useSelectedNetwork(chainId);

const { data: deployedContractData } = useDeployedContractInfo({
contractName,
chainId: selectedNetwork.id as AllowedChainIds,
});

const sendContractWriteAsyncTx = async <
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, "nonpayable" | "payable">,
Expand All @@ -44,12 +51,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(`Wallet is connected to the wrong network. Please switch to ${selectedNetwork.name}`);
return;
}

Expand Down Expand Up @@ -93,12 +101,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(`Wallet is connected to the wrong network. Please switch to ${selectedNetwork.name}`);
return;
}

Expand Down
Loading

0 comments on commit 6a72141

Please sign in to comment.