Particle Network Smart Wallet-as-a-Service


Particle Network Smart Wallet-as-a-Service

Particle Networkopen in new window is the Intent-Centric, Modular Access Layer of Web3. With Particle's Smart Wallet-as-a-Service, developers can curate an unparalleled user experience through modular and customizable EOA/AA embedded wallet components. Using MPC-TSS for key management, Particle can streamline user onboarding via familiar Web2 accounts—such as Google accounts, email addresses, and phone numbers.

Thus, using Particle Network within applications build on COMBO can significantly enhance user experience and consumer-readiness, therefore increasing the potential reach and userbase of your application. Particle supports COMBO Mainnet and Testnet through both EOA interactions and native ERC-4337 SimpleAccount implementations.

Using Particle Network Wallet-as-a-Service for a secure, flexible embedded EOA wallet implementation on COMBO is quite simple and can be achieved through the following steps.

Implementing Particle Network's Smart Wallet-as-a-Service

Installation and setup

We'll be going through the process of leveraging Particle Network's Smart Wallet-as-a-Service within your application on COMBO. For this specific example, we'll be using React alongside Particle Auth Core.

To begin, you'll need to install a number of required libraries, these include the following:

yarn add @particle-network/auth-core-modal @particle-network/chains @particle-network/aa

# OR

npm install @particle-network/auth-core-modal @particle-network/chains @particle-network/aa

With these two libraries installed, you'll need to ensure that you have a React application ready; if you don't have one prepared, you can bootstrap a template with npx create-next-app@latest.

Before diving into configuration of Particle Network, you'll need to ensure that you have three universally required values from the Particle dashboardopen in new window: projectId, clientKey, and appId. These values fundamentally link your application with the dashboard, thereby enabling modal customization, analytics, tracking, and so on.

To retrieve these values, you'll need to head into the Particle dashboardopen in new window, then create a new project alongside a new application. Once this is complete, you can copy the "Project ID", "Client Key", and "App ID," then throw those into your .env file.

Configuration

Now that you've successfully installed the various associated SDKs, spun up a React application, and retrieved your projectId, clientKey, and appId, you're ready to configure Particle Network.

Open your index.tsx file and implement a structure similar to the example shown below, in which AuthCoreContextProvider from @particle-network/auth-core-modal is wrapping your primary App (or other main application) component, passing in various configuration parameters.

import React from 'react';
import ReactDOM from 'react-dom/client';

import { ComboTestnet } from '@particle-network/chains';
import { AuthCoreContextProvider } from '@particle-network/auth-core-modal';

import App from './App';

import('buffer').then(({ Buffer }) => {
  window.Buffer = Buffer;
});

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <AuthCoreContextProvider
      options={{
        projectId: process.env.REACT_APP_PROJECT_ID,
        clientKey: process.env.REACT_APP_CLIENT_KEY,
        appId: process.env.REACT_APP_APP_ID,
        themeType: 'dark', // Optional
        fiatCoin: 'USD', // Optional
        language: 'en', // Optional
        erc4337: { // Optional, but suggested for this tutorial
          name: "SIMPLE",
          version: "1.0.0",
        },
        wallet: { // Optional, but suggested for this tutorial
          visible: true,
          customStyle: {
            supportChains: [ComboTestnet]
          }
        },
      }}
    >
      <App />
    </AuthCoreContextProvider>
  </React.StrictMode>
)

Implementation

With Particle Network configured, you can move onto implementing Particle's Smart Wallet-as-a-Service within your application using various React hooks from @particle-network/auth-core-modal and a custom SmartAccount object from @particle-network/aa.

Although first, you'll need to ensure the latter is properly configured. Configuration of the AA SDK (SmartAccount) should be done through code adjacent to the example below:

const smartAccount = new SmartAccount(provider, {
    projectId: process.env.REACT_APP_PROJECT_ID,
    clientKey: process.env.REACT_APP_CLIENT_KEY,
    appId: process.env.REACT_APP_APP_ID,
    aaOptions: {
      simple: [{ chainId: ComboTestnet.id, version: '1.0.0' }]
    }
  });

smartAccount can then be used either directly to facilitate interaction with Particle's AA SDK, or indirectly through the usage of an EIP-1193 provider object:

const customProvider = new ethers.providers.Web3Provider(new AAWrapProvider(smartAccount), "any");

You're now ready to initiate social login and have users interact with your application through their smart account. A complete example of an App.tsx file with this whole logic implemented can be found below:

import React, { useState, useEffect } from 'react';

import { useEthereum, useConnect, useAuthCore } from '@particle-network/auth-core-modal';
import { ComboTestnet } from '@particle-network/chains';
import { AAWrapProvider, SmartAccount, SendTransactionMode } from '@particle-network/aa';

import { ethers } from 'ethers';
import { notification } from 'antd';

import './App.css';

const App = () => {
  const { provider } = useEthereum();
  const { connect, disconnect } = useConnect();
  const { userInfo } = useAuthCore();

  const [balance, setBalance] = useState(null);

  const smartAccount = new SmartAccount(provider, {
    projectId: process.env.REACT_APP_PROJECT_ID,
    clientKey: process.env.REACT_APP_CLIENT_KEY,
    appId: process.env.REACT_APP_APP_ID,
    aaOptions: {
      simple: [{ chainId: ComboTestnet.id, version: '1.0.0' }]
    }
  });

  const customProvider = new ethers.providers.Web3Provider(new AAWrapProvider(smartAccount, SendTransactionMode.Gasless), "any");

  useEffect(() => {
    if (userInfo) {
      fetchBalance();
    }
  }, [userInfo]);

  const fetchBalance = async () => {
    const balanceResponse = await customProvider.getBalance(await smartAccount.getAddress());

    setBalance(ethers.utils.formatEther(balanceResponse));
  }

  const handleLogin = async (authType) => {
    if (!userInfo) {
      await connect({
        socialType: authType,
        chain: ComboTestnet,
      });
    }
  };

  const executeUserOp = async () => {
    const signer = customProvider.getSigner();

    const tx = {
      to: "0x000000000000000000000000000000000000dEaD",
      value: ethers.utils.parseEther("0.001"),
    };

    const txResponse = await signer.sendTransaction(tx);
    const txReceipt = await txResponse.wait();

    notification.success({
      message: txReceipt.transactionHash
    })
  };

  return (
    <div className="App">
      {!userInfo ? (
        <div className="login-section">
          <button className="sign-button" onClick={() => handleLogin('google')}>Sign in with Google</button>
          <button className="sign-button" onClick={() => handleLogin('twitter')}>Sign in with Twitter</button>
        </div>
      ) : (
        <div className="profile-card">
          <h2>{userInfo.name}</h2>
          <div className="balance-section">
            <small>{balance}/small>
            <button className="sign-message-button" onClick={executeUserOp}>Execute User Operation</button>
            <button className="disconnect-button" onClick={() => disconnect()}>Logout</button>
          </div>
        </div>
      )}
    </div>
  );
};

export default App;

Learn More