Closed zach-is-my-name closed 4 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
Updated issue title as another report from SDK issues reports something similar.
@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.
I'm Chetumal time. (ie Ramsey -1) 😉
Deleted screenshot: ping me for copies if needed
@joshLong145 Is there a different relay server endpoint for Manz / Hab?
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" }})
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
@zach-is-my-name Just confirmed the same API key can be used across all the networks
Thanks @spacesailor24 ! For that! And flagging my issues! 😁
@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 Just a heads up if you provide a
litNodeClient
as an option toLitAuthClient
you do not have to manually pass therelayUrl
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
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
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,
});
@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
.
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
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.
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"
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
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"}
@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 "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.
@DashKash54 Tagging you so you can take a look.
@zach-is-my-name
we have published a new build the first issue regarding the relayUrl
which is no available: 5.0.1
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.
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 };
}
@zach-is-my-name No need to create a separate issue, posted your latest to the node team
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
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
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
Description of the issue
I keep getting network errors when requesting sessionSigs with provider.getSessionSigs().
*Note: I'm clearing localstorage before every run. So *
const [sessionSigs, setSessionSigs] = useLocalStorage("sessionSigs"); shouldn't be a concernt
shouldn't be a concern.