LIT-Protocol / Issues-and-Reports

For bug reports, feature requests, and implementation questions related to Lit Protocol and use of the Lit SDK.
0 stars 0 forks source link

[Charli] Habanero returns sessionSigs but timeout on pkpWalletInstance.signMessage("message") #34

Closed zach-is-my-name closed 4 months ago

zach-is-my-name commented 5 months ago

Description of the issue

I keep getting network errors when requesting sessionSigs with provider.getSessionSigs().

Screenshot from 2024-05-09 21-09-37

*Note: I'm clearing localstorage before every run. So *const [sessionSigs, setSessionSigs] = useLocalStorage("sessionSigs"); shouldn't be a concernt shouldn't be a concern.

// useLitSession.tsx
import {Wallet} from '@ethersproject/wallet'
import { useCallback, useState } from 'react';
import { AuthMethod, SessionSigs } from '@lit-protocol/types';
import { getProviderByAuthMethod } from '../../utils/lit';
import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers';
import { IRelayPKP } from '@lit-protocol/types';
import useLocalStorage from '@rehooks/local-storage';
import { litNodeClient } from '@/utils/litClients';

export default function useLitSession() {
  const [sessionSigs, setSessionSigs] = useLocalStorage("sessionSigs");
  const [sessionLoading, setLoading] = useState(false);
  const [sessionError, setError] = useState();

  const initSession = useCallback(
    async (authMethod: AuthMethod, pkp: IRelayPKP): Promise => {
      setLoading(true);
      setError(undefined);

      try {
        console.log("run initSession");
        console.log('authMethod', authMethod)
        console.log('pkp', pkp)

        let provider;
        try {
          provider = getProviderByAuthMethod(authMethod);
          if (!provider) {
            throw Error('no provider object');
          }
        } catch (e) {
          console.error('error obtaining provider', e);
        }

        if (provider && !sessionSigs) {
          const privateKey = process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_WALLET_DEV as string;
          const walletWithCapacityCredit = new Wallet(privateKey);

          const expiration = new Date(Date.now() + 1000 * 60 * 60 * 24 * 7).toISOString(); // 1 week
          const resourceAbilities = [{ resource: new LitActionResource('*'), ability: LitAbility.PKPSigning }];
          const capacityTokenIdStr = process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_ID_STRING_H as string;

          const { capacityDelegationAuthSig } = await litNodeClient.createCapacityDelegationAuthSig({
            // uses: '1',
            dAppOwnerWallet: walletWithCapacityCredit,
            capacityTokenId: capacityTokenIdStr,
            delegateeAddresses: [pkp.ethAddress],
          });

          const sessionSigs: SessionSigs = await provider.getSessionSigs({
            authMethod,
            pkpPublicKey: pkp.publicKey,
            sessionSigsParams: {
              chain: 'ethereum',
              expiration,
              resourceAbilityRequests: resourceAbilities,
              capacityDelegationAuthSig,
            },
            litNodeClient,
          }).catch(error => { console.error(error); throw new Error('error getSessionSigs') });

          console.log(`setting sessionSigs: `, sessionSigs);
          setSessionSigs(sessionSigs);
        }
      } catch (e) {
        const error = e as Error;
        console.error("initSession: error", error);
        setError(error);
      } finally {
        setLoading(false);
      }
    },
    [setSessionSigs]
  );

  return {
    sessionSigs,
    initSession,
    sessionLoading,
    sessionError,
  };
}
{
    "errorKind": "Unexpected",
    "errorCode": "NodeUnknownError",
    "status": 400,
    "message": "Unknown error occured",
    "correlationId": "lit_c8b7f6cd9b4c6",
    "details": [
        "unexpected error: ECDSA signing failed: unexpected error: unexpected error: Could not process presign: unexpected error: Unable to execute presignature: unexpected error: Received abort from channel for protocol presign, txn_prefix: lit_c8b7f6cd9b4c6 at SystemTime { tv_sec: 1715306781, tv_nsec: 847507783 }"
    ]
}

{
    "errorKind": "Validation",
    "errorCode": "NodeRpcError",
    "status": 502,
    "message": "Lit nodes failed to complete the RPC call possibly due to RPC servers being down or because the RPC call is making an incorrect smart contract call that reverts",
    "correlationId": "lit_c8b7f6cd9b4c6",
    "details": [
        "Error fetching block from hash",
        "validation error: failed to get block when fetching blocks for query: Deserialization Error: expected value at line 1 column 1. Response: error code: 502"
    ]
}```
zach-is-my-name commented 5 months ago

Curiously though I do get one OK response: The balance of the Bad Responses share the same req body as the OK response: Deleted screenshots: ping me for copies if needed

zach-is-my-name commented 5 months ago

Updated issue title as another report from SDK issues reports something similar.

joshLong145 commented 5 months ago

@zach-is-my-name Could you try again? This is an internal timeout on the network's rpc connection. In my own test i was able to get back a signed session.

zach-is-my-name commented 5 months ago

Screenshot from 2024-05-10 10-39-55 I'm Chetumal time. (ie Ramsey -1) 😉

zach-is-my-name commented 5 months ago

Deleted screenshot: ping me for copies if needed

@joshLong145 Is there a different relay server endpoint for Manz / Hab?

glitch003 commented 5 months ago

yes, there are different RPC servers for manzano and habanero, and you can pass these into the AuthClient:

export const RELAY_URL_HABANERO = 'https://habanero-relayer.getlit.dev';
export const RELAY_URL_MANZANO = 'https://manzano-relayer.getlit.dev';

This is a bug - we should use the relayer from the correct network automatically. @joshLong145

So, for habanero, you could use

const litAuthClient = new LitAuthClient({litRelayConfig: { relayUrl: "https://habanero-relayer.getlit.dev", relayApiKey: "yourapikeyhere" }})
zach-is-my-name commented 5 months ago

Thanks @glitch003. Would I also need new a api key than the one I was issued for cayenne? If yes, maybe Wyatt's available to connect with me on discord to obtain that. I'm userzach over there

spacesailor24 commented 5 months ago

@zach-is-my-name Just confirmed the same API key can be used across all the networks

zach-is-my-name commented 5 months ago

Thanks @spacesailor24 ! For that! And flagging my issues! 😁

joshLong145 commented 5 months ago

@zach-is-my-name Just a heads up if you provide a litNodeClient as an option to LitAuthClient you do not have to manually pass the relayUrl

const litAuthClient = new LitAuthClient({
    litNodeClient: "" // your instance of `LitNodeClient`
    litRelayConfig: { relayUrl:  relayApiKey: "yourapikeyhere" }
});

as the Auth Client will pick the RPC URL based on what the instance of LitNodeClient is configured for.

zach-is-my-name commented 5 months ago

@zach-is-my-name Just a heads up if you provide a litNodeClient as an option to LitAuthClient you do not have to manually pass the relayUrl

const litAuthClient = new LitAuthClient({
    litNodeClient: "" // your instance of `LitNodeClient`
    litRelayConfig: { relayUrl:  relayApiKey: "yourapikeyhere" }
});

as the Auth Client will pick the RPC URL based on what the instance of LitNodeClient is configured for.

Even better. Thanks Josh

zach-is-my-name commented 5 months ago

Wait I think I was doing that:

// litClients.tsx
import { LitNodeClient } from '@lit-protocol/lit-node-client';
import { LitAuthClient } from '@lit-protocol/lit-auth-client';
import { LIT_NETWORKS_KEYS } from '@lit-protocol/types';

const litNetwork = process.env.NEXT_PUBLIC_LIT_NETWORK_M as LIT_NETWORKS_KEYS;
if (!litNetwork) throw new Error('problem importing litNetwork env')
export const litNodeClient: LitNodeClient = new LitNodeClient({
  alertWhenUnauthorized: false,
  litNetwork,
  checkNodeAttestation: false,
  debug: true
});

export const litAuthClient: LitAuthClient = new LitAuthClient({
  debug: true,
  litRelayConfig: {
    relayApiKey: process.env.NEXT_PUBLIC_LIT_RELAY_API_KEY,
     relayUrl: process.env.NEXT_PUBLIC_LIT_RELAY_URL_M //just 
       added this on Chris' suggestion
  },
  litNodeClient,
});

But I don't manually call connect() because it was raging through MBs of network handshakes before I even needed Lit:

// useLitClients.ts
import {Wallet} from '@ethersproject/wallet'
import { LitAuthClient } from '@lit-protocol/lit-auth-client';
import { LitNodeClient } from '@lit-protocol/lit-node-client';
import { useEffect } from 'react';

const useLitClients = (litNodeClient: LitNodeClient, litAuthClient: LitAuthClient) => {
  useEffect(() => {
      const connectClients = async () => {
        await litNodeClient.connect().catch(error => {console.error(error); throw new Error('error litNodeClient.connect error')});
    };
    void (async () => {
      // await connectClients().catch(error => {console.error(error); throw new Error('error connectClients()')});
    })();
    return () => {
      void (async () => {
        await litNodeClient.disconnect().catch(error => {console.error(error); throw new Error('error disconnect()')});
      })();
    };
  }, [litNodeClient]);
  return { litNodeClient, litAuthClient };
};

export default useLitClients;

Perhaps that works for you because you call connect manually? I'm grateful for everything but honestly I was passing litNodeClient to the AutClient constructor's obj param the whole time

zach-is-my-name commented 5 months ago

Just tested this (v5): provider.getSessionSigs(..) success

export const litNodeClient: LitNodeClient = new LitNodeClient({
  alertWhenUnauthorized: false,
  litNetwork,
  checkNodeAttestation: false,
  debug: true
});

export const litAuthClient: LitAuthClient = new LitAuthClient({
  debug: true,
  litRelayConfig: {
    relayApiKey: process.env.NEXT_PUBLIC_LIT_RELAY_API_KEY,
    relayUrl: process.env.NEXT_PUBLIC_LIT_RELAY_URL_M
  },
  // litNodeClient,
});

But if I include the litNodeClient in the authClient constructor param object it fails with the timeout

export const litAuthClient: LitAuthClient = new LitAuthClient({
  debug: true,
  litRelayConfig: {
    relayApiKey: process.env.NEXT_PUBLIC_LIT_RELAY_API_KEY,
    relayUrl: process.env.NEXT_PUBLIC_LIT_RELAY_URL_M
  },
  litNodeClient,
});
joshLong145 commented 5 months ago

@zach-is-my-name Thanks for the additional source code. I was able to find a bug in our LitAuthClient constructor which was overriding the relayUrl I have fixed this and will be publishing a new version with this included. So once this is published in 5.0.1 you will no longer need to set your own relayUrl.

zach-is-my-name commented 5 months ago

Thanks Josh I just saw that. Much appreciated. I'll close for now since the unpublished is working on your end and my original issue has been resolved by this investigation

zach-is-my-name commented 5 months ago

Update: Late Sunday, One bad Node blocks the return of provider.getSessionSigs(). See Next Message for latest Network tab screenshot containing Error response message

@glitch003 @joshLong145 I'm very sorry but after returning the provider.getSessionSigs once, maybe twice on manzano and habenero, I can't get seem to get them any more. Additionally I don't think the sig shares were ever valid because my app immediately uses PKPEthers's signMessage to sign a Supabase Auth JWT and that did timeout even when the call to provider.getSessionSigs did not.

My Relevant App Code ``` // litClients.ts import { LitNodeClient } from '@lit-protocol/lit-node-client'; import { LitAuthClient } from '@lit-protocol/lit-auth-client'; import { LIT_NETWORKS_KEYS } from '@lit-protocol/types'; const litNetwork = process.env.NEXT_PUBLIC_LIT_NETWORK_M as LIT_NETWORKS_KEYS; const relayUrl = process.env.NEXT_PUBLIC_LIT_RELAY_URL_M; export const litNodeClient: LitNodeClient = new LitNodeClient({ alertWhenUnauthorized: false, litNetwork, checkNodeAttestation: false, debug: true }); console.log('litNetwork', litNetwork, typeof litNetwork) console.log('relayUrl', relayUrl, typeof relayUrl) export const litAuthClient: LitAuthClient = new LitAuthClient({ debug: true, litRelayConfig: { relayApiKey: process.env.NEXT_PUBLIC_LIT_RELAY_API_KEY, relayUrl }, }); ``` ``` //calling this now (despite the overhead) // useLitClients.ts import {Wallet} from '@ethersproject/wallet' import { LitAuthClient } from '@lit-protocol/lit-auth-client'; import { LitNodeClient } from '@lit-protocol/lit-node-client'; import { useEffect } from 'react'; const useLitClients = (litNodeClient: LitNodeClient, litAuthClient: LitAuthClient) => { useEffect(() => { const connectClients = async () => { await litNodeClient.connect().catch(error => {console.error(error); throw new Error('error litNodeClient.connect error')}); }; void (async () => { await connectClients().catch(error => {console.error(error); throw new Error('error connectClients()')}); })(); return () => { void (async () => { await litNodeClient.disconnect().catch(error => {console.error(error); throw new Error('error disconnect()')}); })(); }; }, [litNodeClient]); return { litNodeClient, litAuthClient }; }; export default useLitClients; ``` ``` //Here's where I call provider.getSessionSigs() // useLitSession.tsx import {Wallet} from '@ethersproject/wallet' import {JsonRpcProvider} from '@ethersproject/providers' // import {hexlify} from '@ethersproject/bytes' import { useCallback, useState } from 'react'; import { AuthMethod, SessionSigs } from '@lit-protocol/types'; import { getProviderByAuthMethod } from '../../utils/lit'; import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers'; import { IRelayPKP } from '@lit-protocol/types'; import useLocalStorage from '@rehooks/local-storage'; import { litNodeClient } from '@/utils/litClients'; export default function useLitSession() { const [sessionSigs, setSessionSigs] = useLocalStorage("sessionSigs"); const [sessionLoading, setLoading] = useState(false); const [sessionError, setError] = useState(); const initSession = useCallback( async (authMethod: AuthMethod, pkp: IRelayPKP): Promise => { setLoading(true); setError(undefined); try { console.log("run initSession"); const resourceAbilities = [{ resource: new LitActionResource('*'), ability: LitAbility.PKPSigning }]; const expiration = new Date(Date.now() + 1000 * 60 * 60 * 24 * 7).toISOString(); // 1 week let provider; try { provider = getProviderByAuthMethod(authMethod); if (!provider) { throw Error('no provider object'); } } catch (e) { console.error('error obtaining provider', e); } if (provider && !sessionSigs) { const privateKey = process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_WALLET_DEV; if (!privateKey) throw new Error("problem importing process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_WALLET_DEV;") const ethersProvider = new JsonRpcProvider("https://chain-rpc.litprotocol.com/http"); const walletWithCapacityCredit = new Wallet(privateKey, ethersProvider); const capacityTokenIdStr = process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_ID_STRING_M; const { capacityDelegationAuthSig } = await litNodeClient.createCapacityDelegationAuthSig({ uses: '1', dAppOwnerWallet: walletWithCapacityCredit, capacityTokenId: capacityTokenIdStr, delegateeAddresses: [pkp.ethAddress], }); const sessionSigs: SessionSigs = await provider.getSessionSigs({ authMethod, pkpPublicKey: pkp.publicKey, sessionSigsParams: { chain: 'ethereum', expiration, resourceAbilityRequests: resourceAbilities, capacityDelegationAuthSig, }, litNodeClient, }).catch(error => { console.error(error); throw new Error('error getSessionSigs') }); console.log(`setting sessionSigs: `, sessionSigs); setSessionSigs(sessionSigs); } } catch (e) { const error = e as Error; console.error("initSession: error", error); setError(error); } finally { setLoading(false); } }, [setSessionSigs] ); return { sessionSigs, initSession, sessionLoading, sessionError, }; } ``` ``` //and here's where the PKPEthers signing failed (because I referenced it earlier in the context of the call to provider.getSessionSigs() //useAuthenticateAndFetchJWT.tsx import { useEffect, useState } from 'react'; import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; import ky from 'ky'; import { useLocalStorage } from '@rehooks/local-storage'; import { IRelayPKP, SessionSigs } from '@lit-protocol/types'; import { isJwtExpired } from '../../utils/app'; import { NonceData } from '../../types/types'; import { useAuthOnboardContext } from '@/contexts'; export function useAuthenticateAndFetchJWT(currentAccount: IRelayPKP | null, sessionSigs: SessionSigs | null) { const [userJWT, setUserJWT] = useLocalStorage("userJWT"); const [nonce, setNonce] = useState(""); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const context = useAuthOnboardContext(); useEffect(() => { if (userJWT && isJwtExpired(userJWT)) { setUserJWT(null); } }, [userJWT]); useEffect(() => { let isMounted = true; const authenticateAndFetchJWT = async (currentNonce: string | null) => { setIsLoading(true); try { if (context?.isLitLoggedIn && sessionSigs && currentAccount && (userJWT === null || isJwtExpired(userJWT) || currentNonce === null)) { // Fetch new nonce let nonceResponse; try { nonceResponse = await ky('https://supabase-auth.zach-greco.workers.dev/nonce').json(); setNonce(nonceResponse.nonce); currentNonce = nonceResponse.nonce; } catch (e) { console.error(e); throw new Error(`error fetching nonce:`); } // Use the nonce to sign a message and fetch a new JWT let pkpWallet; try { pkpWallet = new PKPEthersWallet({ controllerSessionSigs: sessionSigs, pkpPubKey: currentAccount.publicKey, }); } catch (e) { console.error("new PKPEthersWallet", e); throw new Error(`Wallet Constructor: ${e}`); } try { // 401 is still a question of bad sigs I think await pkpWallet.init(); } catch (e) { console.error("pkpWallet.init", e); throw new Error(`error initializing pkpWallet`); } let signature; try { signature = await pkpWallet.signMessage(nonceResponse.nonce); } catch (e) { console.error("problem signing nonce", e); throw new Error('problem signing'); } let jwtResponse; try { console.log('run jwt request'); jwtResponse = await ky.post('https://supabase-auth.zach-greco.workers.dev/jwt', { json: { ethereumAddress: currentAccount.ethAddress, signature, nonce: nonceResponse.nonce }, }).json<{ token: string }>(); setUserJWT(jwtResponse.token); } catch (e) { throw new Error(`problem with jwt request to worker: ${e}`); } } } catch (e) { console.error("Error final catch", e); const errorInstance = e instanceof Error ? e : new Error('An unknown error occurred'); if (isMounted) { setError(errorInstance); } } finally { if (isMounted) { setIsLoading(false); } } }; void (async () => { await authenticateAndFetchJWT(nonce); })(); return () => { isMounted = false; }; }, [currentAccount, sessionSigs, userJWT]); return { cachedJWT: userJWT, nonce, isLoading, error }; } ``` NEXT_PUBLIC_LIT_NETWORK_M="manzano" NEXT_PUBLIC_LIT_RELAY_URL_M="https://manzano-relayer.getlit.dev" NEXT_PUBLIC_LIT_RELAY_API_KEY="E02B0102-DFF4-67E9-3385-5C71096D7CA0_charli" NEXT_PUBLIC_LIT_CAPACITY_TOKEN_ID_STRING_M="1173" NEXT_PUBLIC_LIT_CAPACITY_TOKEN_WALLET_DEV="1ea52b476acbfd7f4b2b8a6b24d831de4576c25ccf1b9d9b1f01018e99d6eebe"

Edit: Will list things I've tried to resolve this

//src/hooks/useSession.ts
import {Wallet} from '@ethersproject/wallet'
import {Wallet} from '@ethersproject/wallet'
import { useCallback, useState } from 'react';
import { AuthMethod } from '@lit-protocol/types';
import { getSessionSigs, litNodeClient } from '../utils/lit';
import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers';
import { IRelayPKP } from '@lit-protocol/types';
import { SessionSigs } from '@lit-protocol/types';

export default function useSession() {
  const [sessionSigs, setSessionSigs] = useState<SessionSigs>();
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<Error>();

  /**
   * Generate session sigs and store new session data
   */
  const initSession = useCallback(
    async (authMethod: AuthMethod, pkp: IRelayPKP): Promise<void> => {
      setLoading(true);
      setError(undefined);
      try {
        // Prepare session sigs params
        const chain = 'ethereum';
        const resourceAbilities = [
          {
            resource: new LitActionResource('*'),
            ability: LitAbility.PKPSigning,
          },
        ];
        const expiration = new Date(
          Date.now() + 1000 * 60 * 60 * 24 * 7
        ).toISOString(); // 1 week
                  const privateKey = process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_WALLET_DEV;
          if (!privateKey) throw new Error("problem importing process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_WALLET_DEV;")
          const ethersProvider = new JsonRpcProvider("https://chain-rpc.litprotocol.com/http");
          const walletWithCapacityCredit = new Wallet(privateKey, ethersProvider  );

          const capacityTokenIdStr = process.env.NEXT_PUBLIC_LIT_CAPACITY_TOKEN_ID_STRING_M;

          const { capacityDelegationAuthSig } = await litNodeClient.createCapacityDelegationAuthSig({
            uses: '1',
            dAppOwnerWallet: walletWithCapacityCredit,
            capacityTokenId: capacityTokenIdStr,
            delegateeAddresses: [pkp.ethAddress],
          });

        // Generate session sigs
        const sessionSigs = await getSessionSigs({
            authMethod,
            pkpPublicKey: pkp.publicKey,
            litNodeClient: litNodeClient,

            sessionSigsParams: {
              chain: 'ethereum',
              expiration,
              resourceAbilityRequests: resourceAbilities,
              capacityDelegationAuthSig,
            },
        });

        setSessionSigs(sessionSigs);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    },
    []
  );
  console.log(sessionSigs);

  return {
    initSession,
    sessionSigs,
    loading,
    error,
  };
}
//src/utils/lit.tsx
import {
  DiscordProvider,
  GoogleProvider,
  EthWalletProvider,
  LitAuthClient,
  BaseProvider,
} from '@lit-protocol/lit-auth-client';
import { LitNodeClient } from '@lit-protocol/lit-node-client';
import {
  AuthMethodScope,
  AuthMethodType,
  ProviderType,
} from '@lit-protocol/constants';
import {
  AuthMethod,
  GetSessionSigsProps,
  IRelayPKP,
  SessionSigs,
  AuthCallbackParams,
  LIT_NETWORKS_KEYS,
} from '@lit-protocol/types';

export const DOMAIN = process.env.NEXT_PUBLIC_DOMAIN || 'localhost';
export const ORIGIN =
  process.env.NEXT_PUBLIC_VERCEL_ENV === 'production'
    ? `https://${DOMAIN}`
    : `http://${DOMAIN}:3000`;

const litNetwork = process.env.NEXT_PUBLIC_LIT_NETWORK_M as LIT_NETWORKS_KEYS;
if (!litNetwork) throw new Error("bad env")

export const litNodeClient: LitNodeClient = new LitNodeClient({
  alertWhenUnauthorized: false,
  litNetwork,
  debug: true,
});

const relayUrl =   process.env.NEXT_PUBLIC_LIT_RELAY_URL_M;

export const litAuthClient: LitAuthClient = new LitAuthClient({
  litRelayConfig: {
    relayApiKey: process.env.NEXT_PUBLIC_LIT_RELAY_API_KEY,
    relayUrl
  },
});

/**
 * Validate provider
 */
export function isSocialLoginSupported(provider: string): boolean {
  return ['google', 'discord'].includes(provider);
}

/**
 * Redirect to Lit login
 */
export async function signInWithGoogle(redirectUri: string): Promise<void> {
  const googleProvider = litAuthClient.initProvider<GoogleProvider>(
    ProviderType.Google,
    { redirectUri }
  );
  await googleProvider.signIn();
}

/**
 * Get auth method object from redirect
 */
export async function authenticateWithGoogle(
  redirectUri: string
): Promise<AuthMethod | undefined> {
  const googleProvider = litAuthClient.initProvider<GoogleProvider>(
    ProviderType.Google,
    { redirectUri }
  );
  const authMethod = await googleProvider.authenticate();
  return authMethod;
}

/**
 * Redirect to Lit login
 */
export async function signInWithDiscord(redirectUri: string): Promise<void> {
  const discordProvider = litAuthClient.initProvider<DiscordProvider>(
    ProviderType.Discord,
    { redirectUri }
  );
  await discordProvider.signIn();
}

/**
 * Get auth method object from redirect
 */
export async function authenticateWithDiscord(
  redirectUri: string
): Promise<AuthMethod | undefined> {
  const discordProvider = litAuthClient.initProvider<DiscordProvider>(
    ProviderType.Discord,
    { redirectUri }
  );
  const authMethod = await discordProvider.authenticate();
  return authMethod;
}

/**
 * Get auth method object by signing a message with an Ethereum wallet
 */
export async function authenticateWithEthWallet(
  address?: string,
  signMessage?: (message: string) => Promise<string>
): Promise<AuthMethod | undefined> {
  const ethWalletProvider = litAuthClient.initProvider<EthWalletProvider>(
    ProviderType.EthWallet,
    {
      domain: DOMAIN,
      origin: ORIGIN,
    }
  );
  const authMethod = await ethWalletProvider.authenticate({
    address,
    signMessage,
  });
  return authMethod;
}

/**
 * Generate session sigs for given params
 */
export async function getSessionSigs({
  pkpPublicKey,
  authMethod,
  sessionSigsParams,
  litNodeClient
}: {
    pkpPublicKey: string;
    authMethod: AuthMethod;
    sessionSigsParams: GetSessionSigsProps;
    litNodeClient: LitNodeClient;
  }): Promise<SessionSigs> {
  const provider = getProviderByAuthMethod(authMethod);
  if (provider) {
    const sessionSigs = await provider.getSessionSigs({
      pkpPublicKey,
      authMethod,
      sessionSigsParams,
      litNodeClient
    });
    return sessionSigs;
  } else {
    throw new Error(
      `Provider not found for auth method type ${authMethod.authMethodType}`
    );
  }
}

export async function updateSessionSigs(
  params: GetSessionSigsProps
): Promise<SessionSigs> {
  const sessionSigs = await litNodeClient.getSessionSigs(params);
  return sessionSigs;
}

/**
 * Fetch PKPs associated with given auth method
 */
export async function getPKPs(authMethod: AuthMethod): Promise<IRelayPKP[]> {
  const provider = getProviderByAuthMethod(authMethod);
  const allPKPs = await provider.fetchPKPsThroughRelayer(authMethod);
  return allPKPs;
}

/**
 * Mint a new PKP for current auth method
 */
export async function mintPKP(authMethod: AuthMethod): Promise<IRelayPKP> {
  const provider = getProviderByAuthMethod(authMethod);
  // Set scope of signing any data
  const options = {
    permittedAuthMethodScopes: [[AuthMethodScope.SignAnything]],
  };

  let txHash: string;
    // Mint PKP through relay server
    txHash = await provider.mintPKPThroughRelayer(authMethod, options);

  const response = await provider.relay.pollRequestUntilTerminalState(txHash);
  if (response.status !== 'Succeeded') {
    throw new Error('Minting failed');
  }
  const newPKP: IRelayPKP = {
    tokenId: response.pkpTokenId,
    publicKey: response.pkpPublicKey,
    ethAddress: response.pkpEthAddress,
  };
  return newPKP;
}

/**
 * Get provider for given auth method
 */
function getProviderByAuthMethod(authMethod: AuthMethod) {
  switch (authMethod.authMethodType) {
    case AuthMethodType.GoogleJwt:
      return litAuthClient.getProvider(ProviderType.Google);
    case AuthMethodType.Discord:
      return litAuthClient.getProvider(ProviderType.Discord);
    case AuthMethodType.EthWallet:
      return litAuthClient.getProvider(ProviderType.EthWallet);
    default:
      return;
  }
}

// src/.local.env (intentionally publishing the api key so anybody can run)
NEXT_PUBLIC_LIT_NETWORK_M="manzano" NEXT_PUBLIC_LIT_RELAY_URL_M="https://manzano-relayer.getlit.dev" NEXT_PUBLIC_LIT_RELAY_API_KEY="E02B0102-DFF4-67E9-3385-5C71096D7CA0_charli" NEXT_PUBLIC_LIT_CAPACITY_TOKEN_ID_STRING_M="1173" NEXT_PUBLIC_LIT_CAPACITY_TOKEN_WALLET_DEV="1ea52b476acbfd7f4b2b8a6b24d831de4576c25ccf1b9d9b1f01018e99d6eebe"

zach-is-my-name commented 5 months ago

Monday Morning EST (no DST) (Habanero) 23.111.254.108 continues to fail with that 502 message:

 "errorKind": "Validation",
    "errorCode": "NodeRpcError",
    "status": 502,
    "message": "Lit nodes failed to complete the RPC call possibly due to RPC servers being down or because the RPC call is making an incorrect smart contract call that reverts",
    "correlationId": "lit_44589f024bb17",
    "details": [
        "Error fetching block from hash",
        "validation error: failed to get block when fetching blocks for query: Deserialization Error: expected value at line 1 column 1. Response: error code: 502"
    ]
}  

@HarryET All the other rpc's then return a 400 indicating your problem potentially lies with 23.111.254.108

Screenshot from 2024-05-12 21-30-39 Screenshot from 2024-05-12 21-29-15

aditya172926 commented 5 months ago

Just tested this (v5): provider.getSessionSigs(..) ~success~

export const litNodeClient: LitNodeClient = new LitNodeClient({
  alertWhenUnauthorized: false,
  litNetwork,
  checkNodeAttestation: false,
  debug: true
});

export const litAuthClient: LitAuthClient = new LitAuthClient({
  debug: true,
  litRelayConfig: {
    relayApiKey: process.env.NEXT_PUBLIC_LIT_RELAY_API_KEY,
    relayUrl: process.env.NEXT_PUBLIC_LIT_RELAY_URL_M
  },
  // litNodeClient,
});

But if I include the litNodeClient in the authClient constructor param object it fails with the timeout

export const litAuthClient: LitAuthClient = new LitAuthClient({
  debug: true,
  litRelayConfig: {
    relayApiKey: process.env.NEXT_PUBLIC_LIT_RELAY_API_KEY,
    relayUrl: process.env.NEXT_PUBLIC_LIT_RELAY_URL_M
  },
  litNodeClient,
});

Hey @zach-is-my-name I am facing this same issue so will tag along here. Also just wanted to clarify, did removing either litNodeClient or relay URL from litAuthClient work? Briefly I was able to generate session Sigs with that fix, but now I am back to the Timeout error.

Network: Habanero Lit Node Client v5.0.0

error log

[Nest] 17924  - 13/05/2024, 9:08:06 pm   ERROR [LitClient] error while attempting to access session signatures: 
{"message":"There was an error getting the signing shares from the nodes","errorCode":"unknown_error","errorKind":"Timeout","status":500,"details":["timeout limit reached timeout limit: 31000ms"],"requestId":"fcd49ce6a4e64"}
zach-is-my-name commented 5 months ago

@aditya172926 "Also just wanted to clarify, did removing either litNodeClient or relay URL from litAuthClient work?" That aligns the relay network rpc's so it won't fail for that reason. After that is overcome (fixed for unpublished 6.0.1) a variety of network errors result from getSessionSigs (provider.getSessionSigs in my case, which is completely different than litNodeClient.getSessionSigs() in your case). Timeouts, 502: "Error fetching block from hash", "couldn't get triple". Are some of the errors for those two methods. Then: Even if you get lucky and have session sigs returned. Trying to do something with them: pkpWalletInstance.signMessage() in my case will fail with a timeout.

aditya172926 commented 5 months ago

@aditya172926 "Also just wanted to clarify, did removing either litNodeClient or relay URL from litAuthClient work?" That aligns the relay network rpc's so it won't fail for that reason. After that is overcome (fixed for unpublished 6.0.1) a variety of network errors result from getSessionSigs (provider.getSessionSigs in my case, which is completely different than litNodeClient.getSessionSigs() in your case). Timeouts, 502: "Error fetching block from hash", "couldn't get triple". Are some of the errors for those two methods. Then: Even if you get lucky and have session sigs returned. Trying to do something with them: pkpWalletInstance.signMessage() in my case will fail with a timeout. I'll be honest it's frustrating because my app is completely reliant on Lit from start to finish, and not having a single functioning network for almost a week (Cayenne returns 0 of 2 signatures) is costing me a lot.

Hmm I see. Well eventually I will have to get to the message and txn signing with pkpWalletInstance. But before that, the timeout error for getSessionSigs will need to be unblocked.

So after reading where this current issue is headed, I think at this point it will be better if I create a separate issue here for the Timeout error.

joshLong145 commented 5 months ago

@DashKash54 Tagging you so you can take a look.

joshLong145 commented 5 months ago

@zach-is-my-name we have published a new build the first issue regarding the relayUrl which is no available: 5.0.1

zach-is-my-name commented 5 months ago

Monday 9:30 PM UTC -5 hours

Habanero returns sessionSigs but timeout on pkpWalletInstance.signMessage("message"). Please advise if I should open a new issue.
Screenshot from 2024-05-13 20-27-45

import { useEffect, useState } from 'react';
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
import ky from 'ky';
import { useLocalStorage } from '@rehooks/local-storage';
import { IRelayPKP, SessionSigs } from '@lit-protocol/types';
import { isJwtExpired } from '../../utils/app';
import { NonceData } from '../../types/types';
import { useAuthOnboardContext } from '@/contexts';

export function useAuthenticateAndFetchJWT(currentAccount: IRelayPKP | null, sessionSigs: SessionSigs | null) {
  const [userJWT, setUserJWT] = useLocalStorage<string | null>("userJWT");
  const [nonce, setNonce] = useState<string | null>("");
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  const context = useAuthOnboardContext();

  useEffect(() => {
    if (userJWT && isJwtExpired(userJWT)) {
      setUserJWT(null);
    }
  }, [userJWT]);

  useEffect(() => {
    let isMounted = true;

    const authenticateAndFetchJWT = async (currentNonce: string | null) => {
      setIsLoading(true);
      try {
        if (context?.isLitLoggedIn && sessionSigs && currentAccount && (userJWT === null || isJwtExpired(userJWT) || currentNonce === null)) {
          // Fetch new nonce
          let nonceResponse = await ky('https://supabase-auth.zach-greco.workers.dev/nonce')
            .json<NonceData>()
            .catch(e => {
              console.error("Error fetching nonce", e);
              throw new Error(`Error fetching nonce: ${e}`);
            });

          if (nonceResponse) {
            console.log('setNonce');
            setNonce(nonceResponse.nonce);
            currentNonce = nonceResponse.nonce;
          } else {
            console.log("setNonce failed");
          }

          // Use the nonce to sign a message and fetch a new JWT
          let pkpWallet = new PKPEthersWallet({
            controllerSessionSigs: sessionSigs,
            pkpPubKey: currentAccount.publicKey,
          });

          await pkpWallet?.init().catch(e => console.error("pkpWallet.init", e));

          if (!nonceResponse?.nonce) throw new Error("no response on nonce");

          let signature = await pkpWallet?.signMessage(nonceResponse.nonce).catch(e => console.error("problem signing nonce", e));

          console.log('run jwt request');
          let jwtResponse = await ky.post('https://supabase-auth.zach-greco.workers.dev/jwt', {
            json: { ethereumAddress: currentAccount.ethAddress, signature, nonce: nonceResponse.nonce },
          })
            .json<{ token: string }>()
            .catch(e => {
              console.error('problem with jwt request to worker', e);
              return null; // Return null if an error occurs
            });

          if (jwtResponse && jwtResponse.token) {
            const token = jwtResponse.token;
            setUserJWT(token);
          } else {
            console.error('Invalid JWT response');
            // Handle the case when the JWT response is invalid or missing the token
          }
        }
      } catch (e) {
        console.error("Error final catch", e);
        const errorInstance = e instanceof Error ? e : new Error('An unknown error occurred');
        if (isMounted) {
          setError(errorInstance);
        }
      } finally {
        if (isMounted) {
          setIsLoading(false);
        }
      }
    };

    void (async () => {
      await authenticateAndFetchJWT(nonce);
    })();

    return () => {
      isMounted = false;
    };
  }, [currentAccount, sessionSigs, userJWT]);

  return { cachedJWT: userJWT, nonce, isLoading, error };
}
spacesailor24 commented 5 months ago

@zach-is-my-name No need to create a separate issue, posted your latest to the node team

glitch003 commented 5 months ago

Hey @zach-is-my-name - I think you have to pass "litNetwork": "habanero" to the new PKPEthersWallet() constructor to make it talk to habanero. by default, PKPEthersWallet will talk to Cayenne

zach-is-my-name commented 5 months ago

Hey @zach-is-my-name - I think you have to pass "litNetwork": "habanero" to the new PKPEthersWallet() constructor to make it talk to habanero. by default, PKPEthersWallet will talk to Cayenne

Very good. Thank you. I was examining the PkpConstructor params late last night until my motherboard fried. I really appreciate the tip and apologize if this thread when a little haywire because I wasn't aware of that. Congrats on the new deploy

zach-is-my-name commented 5 months ago

I’ll be trying this as soon as I get my new machine up and running. If a day or two passes and I don’t report back or close please forgive me. But I will circle back here as soon as I try it