A walkthrough on Particle Network’s Modular Smart Wallet-as-a-Service, leveraging account abstraction and social logins across various providers.
create-react-app
, Particle Auth Core, and Particle’s AA SDK.
create-react-app
template, as shown below.
create-react-app
project.
Within your IDE of choice, run the following command, replacing {name}
with the name of your project.
{name}
. This directory should contain the following structure by default:
src
folder and the files within it. src
will contain the following by default:
App.js
and index.js
files to either .jsx
(JavaScript) or .tsx
(TypeScript).
We will use these two files, App.tsx
and index.tsx
, within this guide.
@particle-network/auth-core-modal
, to directly initiate a social login and drive the usage of an embedded wallet.@particle-network/aa
, for configuring, assigning, and deploying a smart account.@particle-network/chain
, to allow Base to be used within this example.@particle-network
, we’ll be using Ethers for core functions, such as retrieving the user’s balance, sending a gasless transaction, and so on.
For the sake of simplicity, we’ll be using Ethers v5.7.2, the last release before the Ethers v6 upgrade. Although, if you’d like to use a newer version (v6), comments noting the new syntax of v6 will be left on the code snippets throughout this guide.
Thus, you’ll need to install Ethers through either of the following commands:
projectId
, assigned to a project created through the Particle dashboard.clientKey
, similarly assigned to a project created through the dashboard, but serving a different purpose.appId
, retrieved through the creation of an application (within a project) on the dashboard.@particle-network/auth-core-modal
and @particle-network/aa
will require the retrieval and utilization of these three values.
To create a project and an application through the Particle dashboard:
REACT_APP_PROJECT_ID
, REACT_APP_CLIENT_KEY
, and REACT_APP_APP_ID
.
@particle-network/auth-core-modal
(among other dependencies) and retrieved your project ID, client key, and app ID, you’re ready to configure and therefore initialize the Particle Auth Core SDK.
As mentioned, we’ll be working out of two files within this guide:
App.jsx/tsx
, containing our core application logic (such as initiating social login and executing the transaction).index.jsx/tsx
, used in this example for configuring AuthCoreContextProvider
from @particle-network/auth-core-modal
, the core configuration object for Particle Auth Core.AuthCoreContextProvider
is a React component used to define these three aforementioned values, customize the embedded wallet modal and enable account abstraction within it. This will wrap our primary application component (App
from App.jsx/tsx
), therefore allowing Particle Auth Core to be used through various hooks within App
.
To achieve this, AuthCoreContextProvider
will take the following parameters:
projectId
, clientKey
, and appId
. These are the required values previously retrieved from the Particle dashboard.erc4337
, used to define the type of smart account you intend to use, ensuring it’s displayed and reflected within the embedded wallet interface.wallet
, for customizing the embedded wallet interface through the restriction of supported chains, color options, etc.index.jsx/tsx
file may look like given the usage of AuthCoreContextProvider
has been included below.
App.jsx/tsx
, which will contain logic achieving the following:
@particle-network/auth-core-modal
) and base functions on Ethers, which will be automatically powered by AA through the custom EIP-1193 provider object.
These hooks include useEthereum
for the retrieval of the standard EOA-based provider object, useConnect
for managing social logins, and useAuthCore
to retrieve the user’s information (after social login).
To begin building App.jsx/tsx
, you’ll need to define the relevant functions from these hooks through a process similar to the example below:
AuthCoreContextProvider
).
As mentioned, Particle Network supports a variety of smart accounts directly through its AA SDK, these include:
SmartAccount
object (imported from @particle-network/aa
). SmartAccount
acts as the central point for initializing a smart account.
To configure SmartAccount
, you’ll be using the following parameters:
projectId
, clientKey
, and appId
. These were used within AuthCoreContextProvider
and can be retrieved from the Particle dashboard through the same procedure.aaOptions
, which contains accountContracts
. Within accountContracts
, you’ll need to define a property corresponding with the smart account you’d like to use, i.e. BICONOMY
, LIGHT
, CYBERCONNECT
, or SIMPLE
.
chainIds
and version
.SmartAccount
object:
SmartAccount
object, such as with {your object}.sendTransaction
.sendTransaction
or getBalance
through the AA-enabled provider we construct with AAWrapProvider
(imported from @particle-network/aa
).
Essentially, we’ll construct an instance of AAWrapProvider
, passing in the previously defined SmartAccount
object alongside an object representing the method selected to pay gas fees. This will allow Ethers to directly load the smart account and drive transactions/signatures through Particle’s embedded wallet.
You can achieve this in one line of code, e.g.:
SendTransactionMode
has three options. They are:
SendTransactionMode.Gasless
, which will request gas sponsorship on every transaction sent through Ethers. By default, this will be through Particle’s Omnichain Paymaster. If you don’t have enough USDT deposited in the Paymaster to cover the gas fees, or if the transaction fails to meet your sponsorship conditions (set on the Particle dashboard), the user will pay the gas fees themselves.SendTransactionMode.UserPaidNative
, the default method used if SendTransactionMode
is missing from AAWrapProvider
. This forces the user to pay gas fees themselves.SendTransactionMode.UserSelect
, which allows a user to select which gas fee payment mechanism they use (ERC-20 token, native token, or request sponsorship).SendTransactionMode.Gasless
. Because this example uses Base Sepolia, all transactions will automatically be sponsored.
connect
function, defined from the useConnect
hook imported earlier (from @particle-network/auth-core-modal
).
Upon calling connect
, a user will be brought through the social login process, after which an EOA will be generated (through MPC-TSS) and used as a signer for the smart account.
connect
takes the following parameters:
socialType
, the specific social login mechanism you’d like users to go through. If left as an empty string, a generalized social login modal will be shown. Otherwise, use strings such as ‘google’, ‘twitter’, ‘email’, etc.chain
, an object (imported from @particle-network/chains
) corresponding with the chain you’d like to use. In this example, it’ll be BaseSepolia
.connect
isn’t called if a user has already logged in. This can be done by only calling connect
on the condition that userInfo
(from useAuthCore
) is undefined, indicating that the user isn’t logged in.
Below is an example of calling connect
(within the conditional described above).
connect
(or handleLogin
in this example), will be bound to a “Login” or “Connect” button, as will be done here.
SendTransactionMode
) is identical to the flow you’re likely already familiar with. However, it’s important to note that transactions sent through ERC-4337 account abstraction do not follow standard transaction structures, these are called UserOperations.
Typically, UserOperations follow lower-level, alternative structures. Although, through the usage of AAWrapProvider
, the conversion between a simple transaction object (with to
, value
, data
, etc.) to a complete UserOperation is handled automatically, allowing you to send transactions as you would normally.
Thus, we’ll be constructing a simple transaction (tx
) adhering to the following structure:
to
, the recipient address. For this example, we can burn a small amount of ETH on Base Sepolia, which means the recipient will be 0x000000000000000000000000000000000000dEaD
.value
, the value being sent in wei. Because of the default denomination in wei, this will be set as ethers.utils.parseEther("0.001")
.data
can also be filled out (or within Ethers, a Contract
object can be built).
Therefore, your tx
object should look like this:
signer
object retrieved from {your provider}.getSigner()
to call the sendTransaction
method, which simply takes the tx
object we constructed a moment ago.
Upon calling signer.sendTransaction(tx)
, the user will be prompted to confirm the transaction (sign a UserOperation hash) through an application-embedded popup. After doing so, the transaction will immediately be sent on Base Sepolia.
To reflect the transaction hash after its confirmation on-chain, you can call the wait
method on the variable you saved signer.sendTransaction(tx)
to. The resulting object will contain a transactionHash
value.
See the example below for a visualization of this process:
handleLogin
), assigned a smart account (through SmartAccount
), and executed a gasless transaction (through executeUserOp
).
To present all of this to the user and allow them to interact with these functions for themselves, you’ll need to map handleLogin
and executeUserOp
to the JSX of your App
component. This will format the frontend that a user interacts with to test this application.
Essentially, this displays either “Sign in with Google” or “Sign in with Twitter” through custom buttons that are only shown if the user hasn’t logged in (determined through the state of userInfo
). Upon logging in, the user can either call executeUserOp
or disconnect
(which was defined from useConnect
).
Below is an example of what your App.jsx/tsx
file may look at this point. At the bottom of this snippet you’ll find the JSX:
npm run start
or yarn start
.