GoodDollar / GoodWeb3-Mono

mono repo with GoodDollar's web3 UI components and SDK
https://gooddollar-storybook.vercel.app
1 stars 1 forks source link

Fix: possible solution to getFvLink ran before connection #70

Closed L03TJ3 closed 1 year ago

L03TJ3 commented 1 year ago

Description

when there is no connected account and useFvLink is called it fails to initialize the SDK properly, as there is no provider. Since it is a hook we cannot run it conditionally higher-up, else the order-of-hooks rule will be broken

setting fv-link to read-only before connection is a potential solution

johnsmith-gooddollar commented 1 year ago

@L03TJ3 If it won't help then I could suggest to refactor useSDK the following way (splitting it onto 2 hooks):

as this is refactorng, please discuss it with @sirpy !

export const useSDKFactory = (
  readOnly = false,
  type: SdkTypes = "base",
  requiredChainId?: number | undefined,
): any => {
  const { library } = useEthers();
  const { chainId, defaultEnv } = useGetEnvChainId(requiredChainId);
  const rolibrary = useReadOnlyProvider(chainId);

  return useCallback(() =>
    sdkFactory(
      type,
      defaultEnv,
      readOnly,
      library instanceof providers.JsonRpcProvider ? library : undefined,
      rolibrary
    ), [type, defaultEnv, readOnly, library, rolibrary]);
}

export const useSDK = (
  readOnly = false,
  type: SdkTypes = "base",
  requiredChainId?: number | undefined,
): RequestedSdk["sdk"] => {
  const factory = useSDKFactory(readOnly, type, requiredChainId);
  const [sdk, setSdk] = useState<ClaimSDK | SavingsSDK | undefined>(factory);

  // skip first render as sdk already initialized by useState()
  useUpdateEffect(() => void setSdk(factory()), [factory]);
  return sdk;
};

then use factory hook inside useFVLink:

export const useFVLink = (chainId?: number) => {
  const { account } = useEthers();
  const { chainId: defaultChainId } = useGetEnvChainId();
  const sdkFactory = useSDKFactory(false, "claim", chainId ?? defaultChainId);
  const [fvLink, setFVLink] = useState(null);

  useEffect(() => {
    // skip effect if no account
    if (!account) {
      return;
    }

    const sdk = sdkFactory();
    const link = sdk.getFVLink(chainId);

    setFVLink(link);
  }, [account, sdkFactory, chainId]);

  return fvLink;
};
L03TJ3 commented 1 year ago

I did a partial implementation so that no refactor is required and only will be used for now by useFVLink tested, and works

Edit: still updated the useSDKFactory as this was not impacting any hooks using the factory and was duplicated logic