Updated main provider to include Chronicle
This commit is contained in:
parent
19b5dee9d8
commit
4b419a5ade
3
example/google-auth/.eslintrc.json
Normal file
3
example/google-auth/.eslintrc.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "prettier"]
|
||||
}
|
32
example/google-auth/.gitignore
vendored
Normal file
32
example/google-auth/.gitignore
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
3
example/google-auth/.prettierignore
Normal file
3
example/google-auth/.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.prettierrc
|
6
example/google-auth/.prettierrc
Normal file
6
example/google-auth/.prettierrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"arrowParens": "avoid",
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true,
|
||||
"semi": true
|
||||
}
|
25
example/google-auth/README.md
Normal file
25
example/google-auth/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
# PKP x Google OAuth Web Example 🪢
|
||||
|
||||
This is an example web app that shows how you can mint and use programmable key pairs (PKPs) with just Google account. With PKPs, you can build distributed and customizable MPC wallets. Learn more about PKPs [here](https://developer.litprotocol.com/pkp/wallets/intro).
|
||||
|
||||
Check out the [live demo](https://pkp-social-auth-example.vercel.app/).
|
||||
|
||||
## 💻 Getting Started
|
||||
|
||||
1. Clone this repo and install dependencies:
|
||||
|
||||
```bash
|
||||
git clone git@github.com:LIT-Protocol/pkp-social-auth-example.git
|
||||
|
||||
cd pkp-social-auth-example
|
||||
|
||||
yarn install
|
||||
```
|
||||
|
||||
2. Start your development server:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
3. Visit [http://localhost:3000](http://localhost:3000) to start playing with the app.
|
7
example/google-auth/jsconfig.json
Normal file
7
example/google-auth/jsconfig.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
5
example/google-auth/next-env.d.ts
vendored
Normal file
5
example/google-auth/next-env.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
6
example/google-auth/next.config.js
Normal file
6
example/google-auth/next.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
29
example/google-auth/package.json
Normal file
29
example/google-auth/package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "social-auth-next-example",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lit-protocol/auth-helpers": "^2.2.45",
|
||||
"@lit-protocol/lit-auth-client": "^2.2.45",
|
||||
"connectors": "link:@wagmi/core/connectors",
|
||||
"eslint": "8.36.0",
|
||||
"eslint-config-next": "13.2.4",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"ethers": "^5.7.2",
|
||||
"next": "13.2.4",
|
||||
"prettier": "^2.8.8",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"wagmi": "^0.12.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.15.11",
|
||||
"@types/react": "18.0.31"
|
||||
}
|
||||
}
|
6284
example/google-auth/pnpm-lock.yaml
Normal file
6284
example/google-auth/pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
example/google-auth/public/favicon.ico
Normal file
BIN
example/google-auth/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
66
example/google-auth/src/pages/_app.tsx
Normal file
66
example/google-auth/src/pages/_app.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { AppProps } from 'next/app';
|
||||
import { WagmiConfig, createClient, configureChains } from 'wagmi';
|
||||
import { publicProvider } from 'wagmi/providers/public';
|
||||
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect';
|
||||
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc';
|
||||
import { Chain } from 'wagmi/chains';
|
||||
|
||||
const chronicleChain: Chain = {
|
||||
id: 175177,
|
||||
name: 'Chronicle',
|
||||
network: 'chronicle',
|
||||
|
||||
nativeCurrency: {
|
||||
decimals: 18,
|
||||
name: 'Chronicle - Lit Protocol Testnet',
|
||||
symbol: 'LIT',
|
||||
},
|
||||
rpcUrls: {
|
||||
default: {
|
||||
http: ['https://chain-rpc.litprotocol.com/http'],
|
||||
},
|
||||
public: {
|
||||
http: ['https://chain-rpc.litprotocol.com/http'],
|
||||
},
|
||||
},
|
||||
blockExplorers: {
|
||||
default: {
|
||||
name: 'Chronicle - Lit Protocol Testnet',
|
||||
url: 'https://chain.litprotocol.com',
|
||||
},
|
||||
},
|
||||
testnet: true,
|
||||
};
|
||||
|
||||
const { provider, chains } = configureChains(
|
||||
[chronicleChain],
|
||||
[
|
||||
jsonRpcProvider({
|
||||
rpc: chain => ({ http: chain.rpcUrls.default.http[0] }),
|
||||
}),
|
||||
publicProvider(),
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
const client = createClient({
|
||||
autoConnect: true,
|
||||
connectors: [
|
||||
|
||||
new WalletConnectConnector({
|
||||
chains,
|
||||
options: {
|
||||
projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID,
|
||||
},
|
||||
}),
|
||||
],
|
||||
provider,
|
||||
});
|
||||
|
||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<WagmiConfig client={client}>
|
||||
<Component {...pageProps} />
|
||||
</WagmiConfig>
|
||||
);
|
||||
}
|
13
example/google-auth/src/pages/_document.tsx
Normal file
13
example/google-auth/src/pages/_document.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
614
example/google-auth/src/pages/index.tsx
Normal file
614
example/google-auth/src/pages/index.tsx
Normal file
@ -0,0 +1,614 @@
|
||||
import Head from 'next/head';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { LitNodeClient } from '@lit-protocol/lit-node-client';
|
||||
import {
|
||||
LitAuthClient,
|
||||
BaseProvider,
|
||||
GoogleProvider,
|
||||
EthWalletProvider,
|
||||
WebAuthnProvider,
|
||||
isSignInRedirect,
|
||||
getProviderFromUrl,
|
||||
} from '@lit-protocol/lit-auth-client';
|
||||
import { IRelayPKP, AuthMethod, SessionSigs } from '@lit-protocol/types';
|
||||
import { ProviderType } from '@lit-protocol/constants';
|
||||
import { ethers } from 'ethers';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useConnect, useAccount, useDisconnect, Connector } from 'wagmi';
|
||||
import {LitAccessControlConditionResource, LitAbility} from '@lit-protocol/auth-helpers';
|
||||
|
||||
|
||||
// Local dev only: When using npm link, need to update encryption pkg to handle possible ipfs client init error
|
||||
// let ipfsClient = null;
|
||||
// try {
|
||||
// ipfsClient = require("ipfs-http-client");
|
||||
// } catch {}
|
||||
|
||||
enum Views {
|
||||
SIGN_IN = 'sign_in',
|
||||
HANDLE_REDIRECT = 'handle_redirect',
|
||||
REQUEST_AUTHSIG = 'request_authsig',
|
||||
REGISTERING = 'webauthn_registering',
|
||||
REGISTERED = 'webauthn_registered',
|
||||
AUTHENTICATING = 'webauthn_authenticating',
|
||||
FETCHING = 'fetching',
|
||||
FETCHED = 'fetched',
|
||||
MINTING = 'minting',
|
||||
MINTED = 'minted',
|
||||
CREATING_SESSION = 'creating_session',
|
||||
SESSION_CREATED = 'session_created',
|
||||
ERROR = 'error',
|
||||
}
|
||||
|
||||
export default function Dashboard() {
|
||||
const redirectUri = 'http://localhost:3000';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const [view, setView] = useState<Views>(Views.SIGN_IN);
|
||||
const [error, setError] = useState<any>();
|
||||
|
||||
const [litAuthClient, setLitAuthClient] = useState<LitAuthClient>();
|
||||
const [litNodeClient, setLitNodeClient] = useState<LitNodeClient>();
|
||||
const [currentProviderType, setCurrentProviderType] =
|
||||
useState<ProviderType>();
|
||||
const [authMethod, setAuthMethod] = useState<AuthMethod>();
|
||||
const [pkps, setPKPs] = useState<IRelayPKP[]>([]);
|
||||
const [currentPKP, setCurrentPKP] = useState<IRelayPKP>();
|
||||
const [sessionSigs, setSessionSigs] = useState<SessionSigs>();
|
||||
|
||||
const [message, setMessage] = useState<string>('Free the web!');
|
||||
const [signature, setSignature] = useState<string>();
|
||||
const [recoveredAddress, setRecoveredAddress] = useState<string>();
|
||||
const [verified, setVerified] = useState<boolean>(false);
|
||||
|
||||
// Use wagmi to connect one's eth wallet
|
||||
const { connectAsync, connectors } = useConnect({
|
||||
onError(error) {
|
||||
console.error(error);
|
||||
setError(error);
|
||||
},
|
||||
});
|
||||
const { isConnected, connector, address } = useAccount();
|
||||
const { disconnectAsync } = useDisconnect();
|
||||
|
||||
/**
|
||||
* Use wagmi to connect one's eth wallet and then request a signature from one's wallet
|
||||
*/
|
||||
async function handleConnectWallet(c: any) {
|
||||
const { account, chain, connector } = await connectAsync(c);
|
||||
try {
|
||||
await authWithWallet(account, connector);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin auth flow with Google
|
||||
*/
|
||||
async function authWithGoogle() {
|
||||
setCurrentProviderType(ProviderType.Google);
|
||||
const provider = litAuthClient.initProvider<GoogleProvider>(
|
||||
ProviderType.Google
|
||||
);
|
||||
await provider.signIn();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request a signature from one's wallet
|
||||
*/
|
||||
async function authWithWallet(address: string, connector: Connector) {
|
||||
setView(Views.REQUEST_AUTHSIG);
|
||||
|
||||
// Create a function to handle signing messages
|
||||
const signer = await connector.getSigner();
|
||||
const signAuthSig = async (message: string) => {
|
||||
const sig = await signer.signMessage(message);
|
||||
return sig;
|
||||
};
|
||||
|
||||
// Get auth sig
|
||||
const provider = litAuthClient.getProvider(ProviderType.EthWallet);
|
||||
const authMethod = await provider.authenticate({
|
||||
address,
|
||||
signMessage: signAuthSig,
|
||||
});
|
||||
setCurrentProviderType(ProviderType.EthWallet);
|
||||
setAuthMethod(authMethod);
|
||||
|
||||
// Fetch PKPs associated with eth wallet account
|
||||
setView(Views.FETCHING);
|
||||
const pkps: IRelayPKP[] = await provider.fetchPKPsThroughRelayer(
|
||||
authMethod
|
||||
);
|
||||
if (pkps.length > 0) {
|
||||
setPKPs(pkps);
|
||||
}
|
||||
setView(Views.FETCHED);
|
||||
}
|
||||
|
||||
async function registerWithWebAuthn() {
|
||||
setView(Views.REGISTERING);
|
||||
|
||||
try {
|
||||
// Register new PKP
|
||||
const provider = litAuthClient.getProvider(
|
||||
ProviderType.WebAuthn
|
||||
) as WebAuthnProvider;
|
||||
setCurrentProviderType(ProviderType.WebAuthn);
|
||||
const options = await provider.register();
|
||||
|
||||
// Verify registration and mint PKP through relayer
|
||||
const txHash = await provider.verifyAndMintPKPThroughRelayer(options);
|
||||
setView(Views.MINTING);
|
||||
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!,
|
||||
};
|
||||
|
||||
// Add new PKP to list of PKPs
|
||||
const morePKPs: IRelayPKP[] = [...pkps, newPKP];
|
||||
setCurrentPKP(newPKP);
|
||||
setPKPs(morePKPs);
|
||||
|
||||
setView(Views.REGISTERED);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async function authenticateWithWebAuthn() {
|
||||
setView(Views.AUTHENTICATING);
|
||||
|
||||
try {
|
||||
const provider = litAuthClient.getProvider(
|
||||
ProviderType.WebAuthn
|
||||
) as WebAuthnProvider;
|
||||
const authMethod = await provider.authenticate();
|
||||
setAuthMethod(authMethod);
|
||||
|
||||
// Authenticate with a WebAuthn credential and create session sigs with authentication data
|
||||
setView(Views.CREATING_SESSION);
|
||||
|
||||
const litResource = new LitAccessControlConditionResource('*');
|
||||
const sessionSigs = await provider.getSessionSigs({
|
||||
pkpPublicKey: currentPKP.publicKey,
|
||||
authMethod,
|
||||
sessionSigsParams: {
|
||||
chain: 'ethereum',
|
||||
resourceAbilityRequests: [{
|
||||
resource: litResource,
|
||||
ability: LitAbility.PKPSigning
|
||||
}],
|
||||
},
|
||||
});
|
||||
setSessionSigs(sessionSigs);
|
||||
|
||||
setView(Views.SESSION_CREATED);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setAuthMethod(null);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handle redirect from Lit login server
|
||||
*/
|
||||
const handleRedirect = useCallback(
|
||||
async (providerName: string) => {
|
||||
setView(Views.HANDLE_REDIRECT);
|
||||
try {
|
||||
// Get relevant provider
|
||||
let provider: BaseProvider;
|
||||
if (providerName === ProviderType.Google) {
|
||||
provider = litAuthClient.getProvider(ProviderType.Google);
|
||||
}
|
||||
setCurrentProviderType(providerName as ProviderType);
|
||||
|
||||
// Get auth method object that has the OAuth token from redirect callback
|
||||
const authMethod: AuthMethod = await provider.authenticate();
|
||||
setAuthMethod(authMethod);
|
||||
|
||||
// Fetch PKPs associated with social account
|
||||
setView(Views.FETCHING);
|
||||
const pkps: IRelayPKP[] = await provider.fetchPKPsThroughRelayer(
|
||||
authMethod
|
||||
);
|
||||
if (pkps.length > 0) {
|
||||
setPKPs(pkps);
|
||||
}
|
||||
setView(Views.FETCHED);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
|
||||
// Clear url params once we have the OAuth token
|
||||
// Be sure to use the redirect uri route
|
||||
router.replace(window.location.pathname, undefined, { shallow: true });
|
||||
},
|
||||
[litAuthClient, router]
|
||||
);
|
||||
|
||||
/**
|
||||
* Mint a new PKP for current auth method
|
||||
*/
|
||||
async function mint() {
|
||||
setView(Views.MINTING);
|
||||
|
||||
try {
|
||||
// Mint new PKP
|
||||
const provider = litAuthClient.getProvider(currentProviderType);
|
||||
const txHash: string = await provider.mintPKPThroughRelayer(authMethod);
|
||||
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,
|
||||
};
|
||||
|
||||
// Add new PKP to list of PKPs
|
||||
const morePKPs: IRelayPKP[] = [...pkps, newPKP];
|
||||
setPKPs(morePKPs);
|
||||
|
||||
setView(Views.MINTED);
|
||||
setView(Views.CREATING_SESSION);
|
||||
|
||||
// Get session sigs for new PKP
|
||||
await createSession(newPKP);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate session sigs for current PKP and auth method
|
||||
*/
|
||||
async function createSession(pkp: IRelayPKP) {
|
||||
setView(Views.CREATING_SESSION);
|
||||
|
||||
try {
|
||||
const litResource = new LitAccessControlConditionResource('*');
|
||||
// Get session signatures
|
||||
const provider = litAuthClient.getProvider(currentProviderType);
|
||||
const sessionSigs = await provider.getSessionSigs({
|
||||
pkpPublicKey: pkp.publicKey,
|
||||
authMethod,
|
||||
sessionSigsParams: {
|
||||
chain: 'ethereum',
|
||||
resourceAbilityRequests: [{
|
||||
resource: litResource,
|
||||
ability: LitAbility.PKPSigning
|
||||
}],
|
||||
},
|
||||
});
|
||||
setCurrentPKP(pkp);
|
||||
setSessionSigs(sessionSigs);
|
||||
|
||||
setView(Views.SESSION_CREATED);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a message with current PKP
|
||||
*/
|
||||
async function signMessageWithPKP() {
|
||||
try {
|
||||
const toSign = ethers.utils.arrayify(ethers.utils.hashMessage(message));
|
||||
const litActionCode = `
|
||||
const go = async () => {
|
||||
// this requests a signature share from the Lit Node
|
||||
// the signature share will be automatically returned in the response from the node
|
||||
// and combined into a full signature by the LitJsSdk for you to use on the client
|
||||
// all the params (toSign, publicKey, sigName) are passed in from the LitJsSdk.executeJs() function
|
||||
const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName });
|
||||
};
|
||||
go();
|
||||
`;
|
||||
// Sign message
|
||||
// @ts-ignore - complains about no authSig, but we don't need one for this action
|
||||
const results = await litNodeClient.executeJs({
|
||||
code: litActionCode,
|
||||
sessionSigs: sessionSigs,
|
||||
jsParams: {
|
||||
toSign: toSign,
|
||||
publicKey: currentPKP.publicKey,
|
||||
sigName: 'sig1',
|
||||
},
|
||||
});
|
||||
// Get signature
|
||||
const result = results.signatures['sig1'];
|
||||
const signature = ethers.utils.joinSignature({
|
||||
r: '0x' + result.r,
|
||||
s: '0x' + result.s,
|
||||
v: result.recid,
|
||||
});
|
||||
setSignature(signature);
|
||||
|
||||
// Get the address associated with the signature created by signing the message
|
||||
const recoveredAddr = ethers.utils.verifyMessage(message, signature);
|
||||
setRecoveredAddress(recoveredAddr);
|
||||
// Check if the address associated with the signature is the same as the current PKP
|
||||
const verified =
|
||||
currentPKP.ethAddress.toLowerCase() === recoveredAddr.toLowerCase();
|
||||
setVerified(verified);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
* Initialize LitNodeClient and LitAuthClient
|
||||
*/
|
||||
async function initClients() {
|
||||
try {
|
||||
// Set up LitNodeClient and connect to Lit nodes
|
||||
const litNodeClient = new LitNodeClient({
|
||||
litNetwork: 'serrano',
|
||||
debug: false,
|
||||
});
|
||||
await litNodeClient.connect();
|
||||
setLitNodeClient(litNodeClient);
|
||||
|
||||
// Set up LitAuthClient
|
||||
const litAuthClient = new LitAuthClient({
|
||||
litRelayConfig: {
|
||||
relayApiKey: 'test-api-key',
|
||||
},
|
||||
litNodeClient,
|
||||
});
|
||||
|
||||
// Initialize providers
|
||||
litAuthClient.initProvider<GoogleProvider>(ProviderType.Google);
|
||||
litAuthClient.initProvider<EthWalletProvider>(ProviderType.EthWallet);
|
||||
litAuthClient.initProvider<WebAuthnProvider>(ProviderType.WebAuthn);
|
||||
|
||||
setLitAuthClient(litAuthClient);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError(err);
|
||||
setView(Views.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (!litNodeClient) {
|
||||
initClients();
|
||||
}
|
||||
}, [litNodeClient]);
|
||||
|
||||
useEffect(() => {
|
||||
// Check if app has been redirected from Lit login server
|
||||
if (litAuthClient && !authMethod && isSignInRedirect(redirectUri)) {
|
||||
const providerName = getProviderFromUrl();
|
||||
handleRedirect(providerName);
|
||||
}
|
||||
}, [litAuthClient, handleRedirect, authMethod]);
|
||||
|
||||
if (!litNodeClient) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Lit Auth Client</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Create a PKP with just a Google account"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<main>
|
||||
{view === Views.ERROR && (
|
||||
<>
|
||||
<h1>Error</h1>
|
||||
<p>{error.message}</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (sessionSigs) {
|
||||
setView(Views.SESSION_CREATED);
|
||||
} else {
|
||||
if (authMethod) {
|
||||
setView(Views.FETCHED);
|
||||
} else {
|
||||
setView(Views.SIGN_IN);
|
||||
}
|
||||
}
|
||||
setError(null);
|
||||
}}
|
||||
>
|
||||
Got it
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{view === Views.SIGN_IN && (
|
||||
<>
|
||||
<h1>Sign in with Lit</h1>
|
||||
{/* Since eth wallet is connected, prompt user to sign a message or disconnect their wallet */}
|
||||
<>
|
||||
{isConnected ? (
|
||||
<>
|
||||
<button
|
||||
disabled={!connector.ready}
|
||||
key={connector.id}
|
||||
onClick={async () => {
|
||||
setError(null);
|
||||
await authWithWallet(address, connector);
|
||||
}}
|
||||
>
|
||||
Continue with {connector.name}
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
setError(null);
|
||||
await disconnectAsync();
|
||||
}}
|
||||
>
|
||||
Disconnect wallet
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{/* If eth wallet is not connected, show all login options */}
|
||||
<button onClick={authWithGoogle}>Google</button>
|
||||
{connectors.map(connector => (
|
||||
<button
|
||||
disabled={!connector.ready}
|
||||
key={connector.id}
|
||||
onClick={async () => {
|
||||
setError(null);
|
||||
await handleConnectWallet({ connector });
|
||||
}}
|
||||
>
|
||||
{connector.name}
|
||||
</button>
|
||||
))}
|
||||
<button onClick={registerWithWebAuthn}>
|
||||
Register with WebAuthn
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</>
|
||||
)}
|
||||
{view === Views.HANDLE_REDIRECT && (
|
||||
<>
|
||||
<h1>Verifying your identity...</h1>
|
||||
</>
|
||||
)}
|
||||
{view === Views.REQUEST_AUTHSIG && (
|
||||
<>
|
||||
<h1>Check your wallet</h1>
|
||||
</>
|
||||
)}
|
||||
{view === Views.REGISTERING && (
|
||||
<>
|
||||
<h1>Register your passkey</h1>
|
||||
<p>Follow your browser's prompts to create a passkey.</p>
|
||||
</>
|
||||
)}
|
||||
{view === Views.REGISTERED && (
|
||||
<>
|
||||
<h1>Minted!</h1>
|
||||
<p>
|
||||
Authenticate with your newly registered passkey. Continue when
|
||||
you're ready.
|
||||
</p>
|
||||
<button onClick={authenticateWithWebAuthn}>Continue</button>
|
||||
</>
|
||||
)}
|
||||
{view === Views.AUTHENTICATING && (
|
||||
<>
|
||||
<h1>Authenticate with your passkey</h1>
|
||||
<p>Follow your browser's prompts to create a passkey.</p>
|
||||
</>
|
||||
)}
|
||||
{view === Views.FETCHING && (
|
||||
<>
|
||||
<h1>Fetching your PKPs...</h1>
|
||||
</>
|
||||
)}
|
||||
{view === Views.FETCHED && (
|
||||
<>
|
||||
{pkps.length > 0 ? (
|
||||
<>
|
||||
<h1>Select a PKP to continue</h1>
|
||||
{/* Select a PKP to create session sigs for */}
|
||||
<div>
|
||||
{pkps.map(pkp => (
|
||||
<button
|
||||
key={pkp.ethAddress}
|
||||
onClick={async () => await createSession(pkp)}
|
||||
>
|
||||
{pkp.ethAddress}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<hr></hr>
|
||||
{/* Or mint another PKP */}
|
||||
<p>or mint another one:</p>
|
||||
<button onClick={mint}>Mint another PKP</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1>Mint a PKP to continue</h1>
|
||||
<button onClick={mint}>Mint a PKP</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{view === Views.MINTING && (
|
||||
<>
|
||||
<h1>Minting your PKP...</h1>
|
||||
</>
|
||||
)}
|
||||
{view === Views.MINTED && (
|
||||
<>
|
||||
<h1>Minted!</h1>
|
||||
</>
|
||||
)}
|
||||
{view === Views.CREATING_SESSION && (
|
||||
<>
|
||||
<h1>Saving your session...</h1>
|
||||
</>
|
||||
)}
|
||||
{view === Views.SESSION_CREATED && (
|
||||
<>
|
||||
<h1>Ready for the open web</h1>
|
||||
<div>
|
||||
<p>Check out your PKP:</p>
|
||||
<p>{currentPKP.ethAddress}</p>
|
||||
</div>
|
||||
<hr></hr>
|
||||
<div>
|
||||
<p>Sign this message with your PKP:</p>
|
||||
<p>{message}</p>
|
||||
<button onClick={signMessageWithPKP}>Sign message</button>
|
||||
|
||||
{signature && (
|
||||
<>
|
||||
<h3>Your signature:</h3>
|
||||
<p>{signature}</p>
|
||||
<h3>Recovered address:</h3>
|
||||
<p>{recoveredAddress}</p>
|
||||
<h3>Verified:</h3>
|
||||
<p>{verified ? 'true' : 'false'}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
30
example/google-auth/tsconfig.json
Normal file
30
example/google-auth/tsconfig.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"target": "es5"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
56
src/lib/NewProvider.svelte
Normal file
56
src/lib/NewProvider.svelte
Normal file
@ -0,0 +1,56 @@
|
||||
<script>
|
||||
import { configureChains, createConfig } from '@wagmi/core';
|
||||
import { publicProvider } from '@wagmi/core/providers/public';
|
||||
import { WalletConnectConnector } from '@wagmi/core/connectors/walletConnect';
|
||||
import { jsonRpcProvider } from '@wagmi/core/providers/jsonRpc';
|
||||
|
||||
const chronicleChain = {
|
||||
id: 175177,
|
||||
name: 'Chronicle',
|
||||
network: 'chronicle',
|
||||
|
||||
nativeCurrency: {
|
||||
decimals: 18,
|
||||
name: 'Chronicle - Lit Protocol Testnet',
|
||||
symbol: 'LIT'
|
||||
},
|
||||
rpcUrls: {
|
||||
default: {
|
||||
http: ['https://chain-rpc.litprotocol.com/http']
|
||||
},
|
||||
public: {
|
||||
http: ['https://chain-rpc.litprotocol.com/http']
|
||||
}
|
||||
},
|
||||
blockExplorers: {
|
||||
default: {
|
||||
name: 'Chronicle - Lit Protocol Testnet',
|
||||
url: 'https://chain.litprotocol.com'
|
||||
}
|
||||
},
|
||||
testnet: true
|
||||
};
|
||||
|
||||
const { publicClient, chains } = configureChains(
|
||||
[chronicleChain],
|
||||
[
|
||||
jsonRpcProvider({
|
||||
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] })
|
||||
}),
|
||||
publicProvider()
|
||||
]
|
||||
);
|
||||
|
||||
const client = createConfig({
|
||||
autoConnect: true,
|
||||
connectors: [
|
||||
new WalletConnectConnector({
|
||||
chains,
|
||||
options: {
|
||||
projectId: '7db8ca514b865088d90cebec1bf28318'
|
||||
}
|
||||
})
|
||||
],
|
||||
provider
|
||||
});
|
||||
</script>
|
@ -3,13 +3,44 @@
|
||||
import { gnosis } from '@wagmi/core/chains';
|
||||
import { publicProvider } from '@wagmi/core/providers/public';
|
||||
import { InjectedConnector } from '@wagmi/core/connectors/injected';
|
||||
import { WalletConnectConnector } from '@wagmi/core/connectors/walletConnect';
|
||||
import { jsonRpcProvider } from '@wagmi/core/providers/jsonRpc';
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const chronicleChain = {
|
||||
id: 175177,
|
||||
name: 'Chronicle',
|
||||
network: 'chronicle',
|
||||
|
||||
nativeCurrency: {
|
||||
decimals: 18,
|
||||
name: 'Chronicle - Lit Protocol Testnet',
|
||||
symbol: 'LIT'
|
||||
},
|
||||
rpcUrls: {
|
||||
default: {
|
||||
http: ['https://chain-rpc.litprotocol.com/http']
|
||||
},
|
||||
public: {
|
||||
http: ['https://chain-rpc.litprotocol.com/http']
|
||||
}
|
||||
},
|
||||
blockExplorers: {
|
||||
default: {
|
||||
name: 'Chronicle - Lit Protocol Testnet',
|
||||
url: 'https://chain.litprotocol.com'
|
||||
}
|
||||
},
|
||||
testnet: true
|
||||
};
|
||||
|
||||
const { chains, publicClient } = configureChains(
|
||||
[gnosis],
|
||||
[chronicleChain, gnosis],
|
||||
[
|
||||
jsonRpcProvider({
|
||||
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] })
|
||||
}),
|
||||
jsonRpcProvider({
|
||||
rpc: () => ({
|
||||
http: `https://rpc.gnosischain.com/`,
|
||||
@ -23,7 +54,15 @@
|
||||
onMount(() => {
|
||||
createConfig({
|
||||
autoConnect: true,
|
||||
connectors: [new InjectedConnector({ chains })],
|
||||
connectors: [
|
||||
new InjectedConnector({ chains }),
|
||||
new WalletConnectConnector({
|
||||
chains,
|
||||
options: {
|
||||
projectId: '7db8ca514b865088d90cebec1bf28318'
|
||||
}
|
||||
})
|
||||
],
|
||||
publicClient
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user