Etherspot has partnered with Web3Auth, to bring users a frictionless Web3 experience by combining the power of Web3auth’s social login onboarding and Etherspot’s Smart Wallet infrastructure.

Users can easily login with a number of different platforms such as Twitter or Google mail. An Etherspot smart contract wallet is then created for them and they are ready to interact with your dapp.

You should have installed the appropriate Etherspot Prime and Web3Auth packages before proceeding.

Packages

Below is an example of a working Web3Auth social login implementation using the Etherspot Prime SDK.

A full example which you can build and deploy can be found here.

Variables to replace

WEB3AUTH_CHAIN_ID_HEX is the chain id in hex, for example 0xaa36a7 for Sepolia.

For the Etherspot Prime SDK part of this we only look at:

  1. If it’s a chain we support.
  2. Whether it’s a mainnet or test net chain. Then we only generate wallets on either of these.

WEB3AUTH_CLIENT_ID is the web3auth client id specific to your project. You can learn at how to get one here.

Code example

import React from 'react';
import styled from 'styled-components';
import { Web3AuthNoModal } from '@web3auth/no-modal';
import { OpenloginAdapter } from '@web3auth/openlogin-adapter';
import { CHAIN_NAMESPACES, WALLET_ADAPTERS } from '@web3auth/base';
import { Oval } from 'react-loader-spinner';
import { LOGIN_PROVIDER } from '@toruslabs/base-controllers';
import { PrimeSdk, Web3WalletProvider } from '@etherspot/prime-sdk';
import { ethers } from 'ethers';

// Initialise web3auth with our custom values
const web3auth = new Web3AuthNoModal({
  chainConfig: {
    chainNamespace: "eip155",
    chainId: process.env.WEB3AUTH_CHAIN_ID_HEX,
  },
  clientId: process.env.WEB3AUTH_CLIENT_ID as string,
});

// Define the openLoginAdapter
const openloginAdapter = new OpenloginAdapter();
web3auth.configureAdapter(openloginAdapter);

const App = () => {
  const [isConnecting, setIsConnecting] = React.useState(false);
  const [errorMessage, setErrorMessage] = React.useState('');
  const [walletAddress, setWalletAddress] = React.useState('');

  // Logout function to clear web3auth cache
  const logout = async () => {
    setWalletAddress('');
    try {
      await web3auth.logout({ cleanup: true });
      web3auth.clearCache();
    } catch (e) {
      console.error(e);
    }
  }

  // Function to pass in specific platform to web3auth
  // E.g Twitter, gmail
  const loginWithProvider = async (loginProvider: string) => {
    if (isConnecting) return;
    setIsConnecting(true);
    setErrorMessage('');
    setWalletAddress('');
    let newErrorMessage;

    if (web3auth.status !== 'connected') {
      await web3auth.init();
      try {
        // Auth via loginProvider
        await web3auth.connectTo(WALLET_ADAPTERS.OPENLOGIN, {
          loginProvider,
          mfaLevel: 'none',
        });
      } catch (e) {
        // @ts-ignore
        newErrorMessage = e?.message;
      }
    }

    if (newErrorMessage) {
      setErrorMessage(newErrorMessage);
      setIsConnecting(false);
    }

    if (web3auth.status !== 'connected' || !web3auth.provider) {
      setErrorMessage('Something went wrong, please try again later.');
      setIsConnecting(false);
    }

    // Initialising web3Auth Provider as Web3 Injectable
    const mappedProvider = new Web3WalletProvider(web3auth.provider);
    await mappedProvider.refresh();

    // Instantiate Etherspot Prime SDK with wrapped web3auth provider
    const etherspotPrimeSdk = new PrimeSdk(mappedProvider, {
      chainId: ethers.BigNumber.from(process.env.WEB3AUTH_CHAIN_ID_HEX as string).toNumber()
    });
    // Get smart account address
    try {
      const address = await etherspotPrimeSdk.getCounterFactualAddress();
    } catch (e) {
      console.error(e);
    }

    if (!address) {
      setErrorMessage('Something went wrong, please try again later.');
      setIsConnecting(false);
    }

    // Set smart wallet address generated by Etherspot Prime SDK
    setWalletAddress(address);
    setIsConnecting(false);
  }

  // GUI
  return (
    <Wrapper>
      {walletAddress && (
        <ConnectedWallet>
          <ConnectedWalletTitle>
            Your address on Ethereum blockchain:
          </ConnectedWalletTitle>
          <ConnectedWalletText>
            <strong>{walletAddress}</strong>
          </ConnectedWalletText>
          <LogoutButton onClick={logout}>Logout</LogoutButton>
        </ConnectedWallet>
      )}
      {isConnecting && (
        <Oval
          height={30}
          width={30}
          color="#fff"
          secondaryColor="#cc29ff"
          strokeWidth={6}
          strokeWidthSecondary={6}
          wrapperStyle={{ display: 'flex', justifyContent: 'center' }}
        />
      )}
      {!isConnecting && !walletAddress && (
        <>
          <ConnectButton onClick={() => loginWithProvider(LOGIN_PROVIDER.GOOGLE)}>
            Login with Google
          </ConnectButton>
          <ConnectButton onClick={() => loginWithProvider(LOGIN_PROVIDER.LINKEDIN)}>
            Login with LinkedIn
          </ConnectButton>
          <ConnectButton onClick={() => loginWithProvider(LOGIN_PROVIDER.GITHUB)}>
            Login with GitHub
          </ConnectButton>
        </>
      )}
      {errorMessage && <ErrorMessage>{errorMessage}</ErrorMessage>}
    </Wrapper>
  )
}

export default App;