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

[DEVS] Cannot create a SessionSig using a provider (Lit Relayer approach) #44

Open capitaharlock opened 6 days ago

capitaharlock commented 6 days ago

Is there an existing issue for this?

SDK version

6

Lit Network

manzano

Description of the bug/issue

Purpose: We aim to establish a process where an "End user" creates a password and is then shown a private key. From that point onward, we will manage this wallet without any further action required from the End user.

diagram

Problem: "// Generate session signatures" snipet is not working. I am sure one problem is the "authMethod". Looks like this is expecting the authMethod Object instance, but I dont know how to get it, and its also confusing: provider was instantiated using an auth method, but I can't find it in properties or methods list.

Code:

import { ethers } from 'ethers';
import { WebAuthnProvider, LitAuthClient, BaseProvider } from '@lit-protocol/lit-auth-client';
import { LitNodeClient } from '@lit-protocol/lit-node-client';
import { IRelayPKP,SessionSigs } from '@lit-protocol/types';
import { ProviderType } from '@lit-protocol/constants';
import { LitAbility, LitActionResource } from '@lit-protocol/auth-helpers';
import { LitRelayerAddUser } from '@/lib/lit/litRelayer';

const RELAYER_LIT_API = process.env.NEXT_PUBLIC_RELAYER_LIT_API;

export async function createLitWallet(): Promise<{
  userWalletAddress: string;
  newPKP: IRelayPKP;
  sessionSigs: SessionSigs;
}> {

    // Create user's Ethereum wallet
    const userWallet = ethers.Wallet.createRandom();

    // Add user to relayer
    await LitRelayerAddUser([userWallet.address]);

    // Initialize LitNodeClient
    const litNodeClient: LitNodeClient = new LitNodeClient({
      alertWhenUnauthorized: false,
      litNetwork: 'manzano',
      debug: true,
    });

    // Initialize LitAuthClient
    const litAuthClient: LitAuthClient = new LitAuthClient({
      litRelayConfig: {
        relayApiKey: RELAYER_LIT_API,
        debug: true,
      },
      litNodeClient,
    });

    // Initialize WebAuthn provider
    const provider: BaseProvider = litAuthClient.initProvider<WebAuthnProvider>(
      ProviderType.WebAuthn
    );

    // Register new WebAuthn credential and mint PKP
    const options = await provider.register();
    const txHash = await provider.verifyAndMintPKPThroughRelayer(options);
    const response = await provider.relay.pollRequestUntilTerminalState(txHash);

    if (response.status !== 'Succeeded') {
      throw new Error('PKP minting failed');
    }

    // Set new PKP
    const newPKP: IRelayPKP = {
      tokenId: response.pkpTokenId,
      publicKey: response.pkpPublicKey,
      ethAddress: response.pkpEthAddress,
    };

    // Generate session signatures
    const sessionSigs = await provider.getSessionSigs({
      pkpPublicKey: String(newPKP.publicKey),
      authMethod: provider.getAuthMethodId,
      sessionSigsParams: {
        resourceAbilityRequests: [{
          resource: new LitActionResource('*'),
          ability: LitAbility.PKPSigning,
        }],
      },
      LitNodeClient: litNodeClient
    });

    return {
      userWalletAddress: userWallet.address,
      newPKP,
      sessionSigs,
    };

}

More information: I've tried 2 approaches:

1 Using an authenticated provider: The code pasted here.

2 Using server side callback: https://developer.litprotocol.com/sdk/serverless-signing/quick-start#obtaining-asession-signatureon-the-server-side But the callback is not working I can provide this code, but if the approach 1 is working I think is the best option.

Severity of the bug

Well, we are totally stucked here. Without sessions sigs we cannot move forward and work on LitActions and so on.

Steps To Reproduce

errConstructorFunc {message: 'This usually means your JSON body is wrong. Please…lit-js-sdk/api_docs_html/index.html#litnodeclient', errorCode: 'NodeBadInput', errorKind: 'Unexpected', status: 422, details: Array(1), …} details: ['caught rocket 422: bad input error'] errorCode: "NodeBadInput" errorKind: "Unexpected" message: "This usually means your JSON body is wrong. Please check that you have sent over every required JSON parameter and that the types are correct according to the docs here https://lit-protocol.github.io/lit-js-sdk/api_docs_html/index.html#litnodeclient" requestId: "5cd37b7598e77" status: 422

logs

Link to code

No response

Anything else?

Just ask me if you need more. Thanks in advance !

capitaharlock commented 2 days ago

Hi, any chance to take a look on this ?

awisniew207 commented 2 days ago

Hello!

The error seems to be with authMethod, an invalid data error, meaning the datatype is probably incorrect. The method you are using in provider.getSessionSigs, getAuthMethodId, will take an AuthMethod datatype and return the id as a string. However, the authMethod property in getSessionSigs actually expects an object of type AuthMethod, not a string.

With your provider being of type WebAuthnProvider, you might try using the authenticate method instead.

The AuthMethod datatype expected by getSessionSigs will have the format:
{
accessToken: "your access token here",
authMethodType: 3,

}

If you are looking for more information on AuthMethod datatypes, it can be found here.
A similar implementation of authMethods can be found here. Please note that in the linked implementation, authMethods is plural, which is slightly different from yours.

If you need additional support with this issue, please reach out!

capitaharlock commented 1 day ago

Thanks for your response! While waiting, I continued evolving the code in search of a solution. Sorry about that. We had a chat with the Lit Protocol staff, and I have been updating the code changes there.

I am now with EthWalletProvider and already using the authenticate method to create the AuthMethod object: return provider.authenticate({ address: ethersSigner.address, signMessage })

This AuthMethod object can be used to mint PKPs, but an error occurs on the nodes when trying to get the SessionSigs.

image

Would you mind to take a look at this one ? Thanks !!

CODE: `import { ethers } from "ethers" import { LitAuthClient, EthWalletProvider } from "@/lib/external/lit-auth-client" import { LitNodeClient } from "@/lib/external/lit-node-client" import { AuthMethod, IRelayPKP, LIT_NETWORKS_KEYS } from "@lit-protocol/types" import { AuthMethodScope, ProviderType } from "@lit-protocol/constants" import { LitAbility, LitPKPResource, LitActionResource, createSiweMessageWithRecaps, generateAuthSig } from "@lit-protocol/auth-helpers"

const LIT_NETWORK: LIT_NETWORKS_KEYS = process.env.NEXT_PUBLIC_LIT_NETWORK as LIT_NETWORKS_KEYS const RELAYER_LIT_API = process.env.NEXT_PUBLIC_RELAYER_LIT_API const DOMAIN = process.env.NEXT_PUBLIC_DOMAIN || "" const ORIGIN = process.env.NEXT_PUBLIC_ORIGIN || ""

interface AuthUserKeys { address: string privateKey: string }

export async function createLitWallet(): Promise { console.log("Starting createLitWallet process...") clearBrowserData()

const authUserKeys = createAuthUserKeys()
const ethersSigner = createEthersSigner(authUserKeys.privateKey)
const { litNodeClient, litAuthClient } = await initializeLitClients()
const provider = initializeProvider(litAuthClient)
const authMethod = await authenticateProvider(provider, ethersSigner, litNodeClient)
const newPKP = await mintPKP(provider, authMethod)
const pkpSessionSigs = await createPKPSessionSigs(litNodeClient, newPKP, authMethod) //, provider, ethersSigner
await litNodeClient.disconnect()
return newPKP

}

function createAuthUserKeys(): AuthUserKeys { const randomWallet = ethers.Wallet.createRandom() return { address: randomWallet.address, privateKey: randomWallet.privateKey, } }

function createEthersSigner(privateKey: string): ethers.Wallet { return new ethers.Wallet(privateKey, new ethers.providers.JsonRpcProvider("https://chain-rpc.litprotocol.com/http")) }

async function initializeLitClients() { const litNodeClient = new LitNodeClient({ alertWhenUnauthorized: false, litNetwork: LIT_NETWORK, debug: true, }) await litNodeClient.connect()

const litAuthClient = new LitAuthClient({
    litRelayConfig: {
        relayApiKey: RELAYER_LIT_API!,
        debug: true,
    },
    litNodeClient,
})

return { litNodeClient, litAuthClient }

}

function initializeProvider(litAuthClient: LitAuthClient): EthWalletProvider { if (!DOMAIN || !ORIGIN) { throw new Error("DOMAIN and ORIGIN must be set in environment variables") } return litAuthClient.initProvider(ProviderType.EthWallet, { domain: DOMAIN, origin: ORIGIN, }) }

async function authenticateProvider(provider: EthWalletProvider, ethersSigner: ethers.Wallet, litNodeClient: LitNodeClient): Promise { const signMessage = async ({ expiration, uri }) => { const toSign = await createSiweMessageWithRecaps({ walletAddress: ethersSigner.address, nonce: await litNodeClient.getLatestBlockhash(), uri, expiration, resources: [ { resource: new LitPKPResource(""), ability: LitAbility.PKPSigning }, { resource: new LitActionResource(""), ability: LitAbility.LitActionExecution }, ], litNodeClient, domain: DOMAIN, }) return generateAuthSig({ signer: ethersSigner, toSign }) }

return provider.authenticate({ address: ethersSigner.address, signMessage })

}

async function mintPKP(provider: EthWalletProvider, authMethod: AuthMethod): Promise { const options = { permittedAuthMethodScopes: [[AuthMethodScope.SignAnything]] } const mintTx = await provider.mintPKPThroughRelayer(authMethod, options) const response = await provider.relay.pollRequestUntilTerminalState(mintTx)

if (response.status !== "Succeeded") {
    throw new Error("Minting failed")
}

return {
    tokenId: response.pkpTokenId,
    publicKey: response.pkpPublicKey,
    ethAddress: response.pkpEthAddress,
}

}

async function createPKPSessionSigs(litNodeClient: LitNodeClient, newPKP: IRelayPKP, authMethod: AuthMethod) { const expirationTime = new Date(Date.now() + 5 60 1000) // 5 min return litNodeClient.getPkpSessionSigs({ pkpPublicKey: newPKP.publicKey, authMethods: [authMethod], resourceAbilityRequests: [ { resource: new LitPKPResource(""), ability: LitAbility.PKPSigning }, { resource: new LitActionResource(""), ability: LitAbility.LitActionExecution }, ], expiration: expirationTime.toISOString(), }) }

function clearBrowserData(): void { document.cookie.split(";").forEach((cookie) => { document.cookie = cookie.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/") }) localStorage.clear() sessionStorage.clear() console.log("Browser data cleared.") } `

awisniew207 commented 1 day ago

Hello again!

I think I might have found the issue. This function:

async function authenticateProvider(provider: EthWalletProvider, ethersSigner: ethers.Wallet, litNodeClient: LitNodeClient): Promise {
    const signMessage = async ({ expiration, uri }) => {
        const toSign = await createSiweMessageWithRecaps({
        walletAddress: ethersSigner.address,
        nonce: await litNodeClient.getLatestBlockhash(),
        uri,
        expiration,
        resources: [
        { resource: new LitPKPResource(""), ability: LitAbility.PKPSigning },
        { resource: new LitActionResource(""), ability: LitAbility.LitActionExecution },
        ],
        litNodeClient,
        domain: DOMAIN,
        })
        return generateAuthSig({ signer: ethersSigner, toSign })
    }
  return provider.authenticate({ address: ethersSigner.address, signMessage })
  }

The second return attempts to return type AuthMethod using the authenticate method; however, the second parameter signMessage is of type AuthSig which is not supported by EthWalletProvider's authenticate method. I believe this could be the issue because of the parsing error received when using getPkpSessionSigs, considering that AuthMethod expects primarily strings and received a map. More on the supported parameter types can be found here.

Please let me know if this helps! All-in-all, I would just make sure your parameters are of the correct type!

capitaharlock commented 21 hours ago

Hello guys, I did try to test the examples on the sdk repo and I was founding the same errors. In this case I did authenticate with google, using the demo-pkp-session-sigs code, without alteration. It gets a SIWE error when reaching the nodes. In my other code approches I did get the same one. At the moment, I am getting another error, mentioned in my previous comment.

I am just sending it in case it helps to find out whats the problem in my code. Thanks again !

image image

image
awisniew207 commented 13 hours ago

Hello!

The issue you are currently having is because of getSessionSigs, which is because we have to update lit-auth-client on our end. This is why you received the same error using getSessionSigs in the demo-pkp-session-sigs code.

The current resolution to this is using getPkpSessionSigs, which you have in the most recent code you have sent (you may have to remove the LitAction ability).

    const sessionSigs = await litNodeClient.getPkpSessionSigs({
      pkpPublicKey: newPKP.publicKey,
      authMethods: [authMethod],
      resourceAbilityRequests: [
        {
          resource: new LitPKPResource('*'),
          ability: LitAbility.PKPSigning,
        },
        {
          resource: new LitActionResource('*'),
          ability: LitAbility.LitActionExecution,
        },
      ],
    });


If this solution does not work for you, would you mind sending the most updated version of your code with the current errors so I could debug it?

Thanks!

capitaharlock commented 9 hours ago

I don't think it can be avoided looking at the code.

If sent empty:

image

If removed key:

image

I will setup a simple repo that can be just downloaded and runned so It can help you to debug.

Anyway, would it be possible to get a working example from your side ? I mean, I just need to see a background code (nodejs) using litrelayer (to pay for gas to any wallet I add), using an Eth auth provider (so we dont need to prompt a wallet window) to be able to use the new wrapped keys feature, and obviously to run Lit actions. I couldn't find any updated or working example around this approach.

I really appreacciate your help ! Thanks for your time