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

Wagmi compatibility hooks #86

Open
borgbob opened this issue Mar 2, 2024 · 5 comments
Open

Wagmi compatibility hooks #86

borgbob opened this issue Mar 2, 2024 · 5 comments

Comments

@borgbob
Copy link

borgbob commented Mar 2, 2024

Hi

I started working on an alternative frontend which uses this SDK with wagmi/viem. The frontend is part of Avalanche deployment of EAS which is being led by @cryptofish7: https://github.com/avax-attestations/aas-frontend

In the docs I found a link to a gist with some hooks which wrapped wagmi/viem clients in ethers compatible signer/provider, but the code was outdated (it was targeting ethers v5) so I had to adapt it. Here's the updated code which works with ethers v6:

// useProvider.ts
import { JsonRpcProvider, FallbackProvider } from "ethers";
import { type PublicClient } from "viem";
import { useState, useEffect } from "react";
import { usePublicClient } from "wagmi";


function publicClientToProvider(publicClient: PublicClient) {
  const { chain, transport } = publicClient;
  if (!chain) {
    return;
  }

  const network = {
    chainId: chain.id,
    name: chain.name,
    ensAddress: chain.contracts?.ensRegistry?.address
  };

  if (transport.type === "fallback") {
    return new FallbackProvider(
      (transport.transports).map(
        ({ value }: any) => new JsonRpcProvider(value?.url, network)
      )
    );
  }

  return new JsonRpcProvider(transport.url, network);
}

type Provider = ReturnType<typeof publicClientToProvider>

export function useProvider() {
  const publicClient = usePublicClient();
  const [provider, setProvider] = useState<Provider | undefined>(undefined);

  useEffect(() => {
    if (publicClient) {
      setProvider(publicClientToProvider(publicClient));
    }
  }, [publicClient]);

  return provider;
}
// useSigner.ts
import { useEffect, useState } from "react";
import { useWalletClient } from "wagmi";
import { type WalletClient } from "viem";
import { BrowserProvider, JsonRpcSigner } from "ethers";

export async function walletClientToSigner(walletClient: WalletClient) {
  const { account, chain, transport } = walletClient;
  if (!chain || !account) {
    return;
  }

  const network = {
    chainId: chain.id,
    name: chain.name,
    ensAddress: chain.contracts?.ensRegistry?.address
  };

  const provider = new BrowserProvider(transport, network);
  const signer = await provider.getSigner(account.address);

  return signer;
}

export function useSigner() {
  const { data: walletClient } = useWalletClient();

  const [signer, setSigner] = useState<JsonRpcSigner | undefined>(undefined);

  useEffect(() => {
    if (walletClient) {
      walletClientToSigner(walletClient).then((signer) => {
        setSigner(signer);
      })
    }
  }, [walletClient]);

  return signer;
}

If you want, I can create a PR that adds these hooks to a new module (wagmi-compat.ts) so that this functionality is more easily available to SDK users. The module would not be referenced by other modules in this package and users would have to import it directly with something like:

import { useSigner, useProvider } from "@ethereum-attestation-service/eas-sdk/wagmi-compat"

I would also add viem, wagmi and react as peer dependencies.

@lbeder
Copy link
Member

lbeder commented Mar 3, 2024

Hey @borgbob, this is great. It'd be amazing if you can indeed go ahead an open this as a PR (+ a very simple test) and I'll be more than happy to review and merge 🙏

@mubarakone
Copy link

@borgbob I followed your steps, however signer is not the same type as the argument for the eas.connect() function. What did you do to get that to work?

image

So far this is what I came up with, not sure if this works so please don't quote me:

import { SignerOrProvider } from '@ethereum-attestation-service/eas-sdk/dist/transaction';
const eas = new EAS(EASContractAddress);
    if (!signer) {
      return
    } else {
      eas.connect(signer as unknown as SignerOrProvider);
    }

Someone let me know what is the correct way to fix this.

@borgbob
Copy link
Author

borgbob commented Mar 4, 2024

@mubarakone the return value of useSigner can be undefined when the component first mounts (and also when the wallet is not connected)

What I did in aas-frontend was create EAS in the submit handler after checking the signer was not undefined, here's how it looks like: https://github.com/avax-attestations/aas-frontend/blob/main/pages/schema/create.tsx#L77-L87

@mubarakone
Copy link

I get this error in your useSigner.ts file:

image

Not sure what this means. But I am also using Account Abstraction, so it could be related to that.

@borgbob
Copy link
Author

borgbob commented Mar 5, 2024

@mubarakone if you are using an account abstraction, can you check if it correctly implements account.address? Also please check if the wagmi/viem versions are compatible with the ones used in aas-frontend

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

No branches or pull requests

3 participants