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

Merged
merged 18 commits into from
Dec 16, 2024

Conversation

JacobHomanics
Copy link
Contributor

Description

Provides the option to pass a different network into the scaffold hooks than the one that the user's wallet is currently connected to. This allows for applications that can show data from different blockchains than that of which the user's wallet is connected to. The hooks still abide by the rules that the contract instance's need to be within the deployedContracts file and targetNetworks needs to have the expected chain(s) present.

live example: https://scaffold-eth-optional-chains-example-nextjs.vercel.app/
live example repo: https://github.com/Hotmanics/scaffold-eth-optionalChainsExample

Additional Information

Your ENS/address: jacobhomanics.eth

@JacobHomanics
Copy link
Contributor Author

Any more thoughts on this?

@technophile-04
Copy link
Collaborator

Hey @JacobHomanics love this and very helpful!

Some initial thoughts, on ideally how the API should look like:

  1. We should let people pass chainId instead of whole chain object.
    • The chainId which people would be passing needs to be typesfafe (like we should only allow chainId's from targetNetworks chains and not any chain)
        const { data: deployedContractData, isLoading: deployedContractLoading } = useDeployedContractInfo({
          contractName: "YourContract",
          chainId: mainnet.id}
        );
  2. I agree Optional chain parameter in Scaffold hooks #931 (comment)! I think now we have good reason to have them as object(contractName + ?chainId), So let's do that!

@JacobHomanics
Copy link
Contributor Author

Great! I've taken ya'lls feedback into consideration. Let me know your updated thoughts on the modifications!

@technophile-04 @rin-st

Copy link
Member

@rin-st rin-st left a comment

Choose a reason for hiding this comment

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

Thanks for updates @JacobHomanics ! Overall looking good!

Added some nitpicks. Also, before merging this we need to add PR to update docs and merge those two PRs together

packages/nextjs/hooks/scaffold-eth/useAllowedNetwork.ts Outdated Show resolved Hide resolved
packages/nextjs/hooks/scaffold-eth/useNetworkColor.ts Outdated Show resolved Hide resolved
packages/nextjs/utils/scaffold-eth/networks.ts Outdated Show resolved Hide resolved
packages/nextjs/utils/scaffold-eth/networks.ts Outdated Show resolved Hide resolved
@JacobHomanics
Copy link
Contributor Author

Everything else has been accounted for! @rin-st

Let me know of any more proposed changes, then will try my hand at updating the docs.

@rin-st
Copy link
Member

rin-st commented Dec 10, 2024

Great, thank you!

Let me know of any more proposed changes, then will try my hand at updating the docs.

For me, just #931 (comment)

Copy link
Collaborator

@technophile-04 technophile-04 left a comment

Choose a reason for hiding this comment

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

This is amazing and works great! Tsym @JacobHomanics!!

@JacobHomanics do you want to make a PR to the SE-2 docs? Lets keep it simple and minimal. I think we just need to do this changes:

  1. Replace 1 param with object for the changed hooks
  2. Add chainId to accepted params tables for the respective hoooks

If anyone wants to test:

  1. Copy this in deployedContracts.ts
`deployedContracts.ts`
/**
 * This file is autogenerated by Scaffold-ETH.
 * You should not edit it manually or your changes might be overwritten.
 */
import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";

const deployedContracts = {
  31337: {
    YourContract: {
      address: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
      abi: [
        {
          inputs: [
            {
              internalType: "address",
              name: "_owner",
              type: "address",
            },
          ],
          stateMutability: "nonpayable",
          type: "constructor",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "address",
              name: "greetingSetter",
              type: "address",
            },
            {
              indexed: false,
              internalType: "string",
              name: "newGreeting",
              type: "string",
            },
            {
              indexed: false,
              internalType: "bool",
              name: "premium",
              type: "bool",
            },
            {
              indexed: false,
              internalType: "uint256",
              name: "value",
              type: "uint256",
            },
          ],
          name: "GreetingChange",
          type: "event",
        },
        {
          inputs: [],
          name: "greeting",
          outputs: [
            {
              internalType: "string",
              name: "",
              type: "string",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "owner",
          outputs: [
            {
              internalType: "address",
              name: "",
              type: "address",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "premium",
          outputs: [
            {
              internalType: "bool",
              name: "",
              type: "bool",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "string",
              name: "_newGreeting",
              type: "string",
            },
          ],
          name: "setGreeting",
          outputs: [],
          stateMutability: "payable",
          type: "function",
        },
        {
          inputs: [],
          name: "totalCounter",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "address",
              name: "",
              type: "address",
            },
          ],
          name: "userGreetingCounter",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "withdraw",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
        {
          stateMutability: "payable",
          type: "receive",
        },
      ],
      inheritedFunctions: {},
    },
  },
  84532: {
    YourContract: {
      address: "0x9Bf3fBCFc62109562bC8bB1F9b092eF285030B22",
      abi: [
        {
          inputs: [
            {
              internalType: "address",
              name: "_owner",
              type: "address",
            },
          ],
          stateMutability: "nonpayable",
          type: "constructor",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "address",
              name: "greetingSetter",
              type: "address",
            },
            {
              indexed: false,
              internalType: "string",
              name: "newGreeting",
              type: "string",
            },
            {
              indexed: false,
              internalType: "bool",
              name: "premium",
              type: "bool",
            },
            {
              indexed: false,
              internalType: "uint256",
              name: "value",
              type: "uint256",
            },
          ],
          name: "GreetingChange",
          type: "event",
        },
        {
          inputs: [],
          name: "greeting",
          outputs: [
            {
              internalType: "string",
              name: "",
              type: "string",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "owner",
          outputs: [
            {
              internalType: "address",
              name: "",
              type: "address",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "premium",
          outputs: [
            {
              internalType: "bool",
              name: "",
              type: "bool",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "string",
              name: "_newGreeting",
              type: "string",
            },
          ],
          name: "setGreeting",
          outputs: [],
          stateMutability: "payable",
          type: "function",
        },
        {
          inputs: [],
          name: "totalCounter",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "address",
              name: "",
              type: "address",
            },
          ],
          name: "userGreetingCounter",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "withdraw",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
        {
          stateMutability: "payable",
          type: "receive",
        },
      ],
      inheritedFunctions: {},
    },
  },
  11155420: {
    YourContract: {
      address: "0x4D634e9BD2646Eb5Aa085bF4f4D76B62B2d3655f",
      abi: [
        {
          inputs: [
            {
              internalType: "address",
              name: "_owner",
              type: "address",
            },
          ],
          stateMutability: "nonpayable",
          type: "constructor",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "address",
              name: "greetingSetter",
              type: "address",
            },
            {
              indexed: false,
              internalType: "string",
              name: "newGreeting",
              type: "string",
            },
            {
              indexed: false,
              internalType: "bool",
              name: "premium",
              type: "bool",
            },
            {
              indexed: false,
              internalType: "uint256",
              name: "value",
              type: "uint256",
            },
          ],
          name: "GreetingChange",
          type: "event",
        },
        {
          inputs: [],
          name: "greeting",
          outputs: [
            {
              internalType: "string",
              name: "",
              type: "string",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "owner",
          outputs: [
            {
              internalType: "address",
              name: "",
              type: "address",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "premium",
          outputs: [
            {
              internalType: "bool",
              name: "",
              type: "bool",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "string",
              name: "_newGreeting",
              type: "string",
            },
          ],
          name: "setGreeting",
          outputs: [],
          stateMutability: "payable",
          type: "function",
        },
        {
          inputs: [],
          name: "totalCounter",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "address",
              name: "",
              type: "address",
            },
          ],
          name: "userGreetingCounter",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "withdraw",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
        {
          stateMutability: "payable",
          type: "receive",
        },
      ],
      inheritedFunctions: {},
    },
  },
} as const;

export default deployedContracts satisfies GenericContractsDeclaration;
  1. Update the scaffold.config to have [chains.baseSepolia, chains.optimismSepolia]

  2. Update page.tsx with this:

`page.tsx`
"use client";

import { useState } from "react";
import type { NextPage } from "next";
import { optimismSepolia } from "viem/chains";
import { InputBase } from "~~/components/scaffold-eth";
import { useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth";

const Home: NextPage = () => {
  const [greeting, setGreeting] = useState("");

  const { data: greetingOnUserSelectedChain } = useScaffoldReadContract({
    contractName: "YourContract",
    functionName: "greeting",
  });

  const { data: greetingOnOPSepolia } = useScaffoldReadContract({
    contractName: "YourContract",
    functionName: "greeting",
    chainId: optimismSepolia.id,
  });

  const { writeContractAsync: writeContractAsyncOnUserChain } = useScaffoldWriteContract({
    contractName: "YourContract",
  });

  const { writeContractAsync: writeContractAsyncOPSepolia } = useScaffoldWriteContract({
    contractName: "YourContract",
    chainId: optimismSepolia.id,
  });

  return (
    <>
      <div className="flex items-center flex-col flex-grow pt-10">
        <InputBase value={greeting} onChange={setGreeting} />

        <button
          className="btn btn-primary mt-4"
          onClick={async () => {
            try {
              await writeContractAsyncOPSepolia({ functionName: "setGreeting", args: [greeting] });
            } catch (e) {
              console.error(e);
            }
          }}
        >
          Write on OP Sepolia
        </button>

        <button
          className="btn btn-primary mt-4"
          onClick={async () => {
            try {
              await writeContractAsyncOnUserChain({ functionName: "setGreeting", args: [greeting] });
            } catch (e) {
              console.error(e);
            }
          }}
        >
          Write on connectChain
        </button>

        <p className="mt-4">Greeting on OP Sepolia: {greetingOnOPSepolia}</p>

        <p className="mt-4">Greeting on connectChain: {greetingOnUserSelectedChain}</p>
      </div>
    </>
  );
};

export default Home;

@technophile-04 technophile-04 merged commit 2a32e1a into scaffold-eth:main Dec 16, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants