Unity (C#) - Connect

Leveraging Particle Connect within mobile applications built on Unity

Particle Connect for Unity

Particle Connect acts as a central wallet connection mechanism within games built on Unity. With it, you can onboard users into a completely functional account through either social logins (via Particle Auth) or typical Web3 wallets (via WalletConnect, Solana's wallet-adapter, or private key imports). This creates a Web2-adjacent login experience while retaining unified compatibility with existing popular Web3 wallets.

Particle Connect has a dedicated Unity SDK for integration; the configuration process and examples of utilization are outlined below.

Repository

Before diving in, all of the Particle Network Unity SDKs (for Particle Auth and Particle Connect) are publicly available and viewable through the official repository. Feel free to look at the underlying architecture and demos showcasing end-to-end implementation for an initial understanding of working with Particle Connect on Unity.

🚧

It is strongly discouraged to use private key or mnemonic import/generate function. If you use it, you need to secure the data yourself, Particle keeps no relationship with the imported/generated mnemonic or private key.

Getting Started

Prerequisites

To start, your Unity project will need to meet several requirements to avoid any compatibility issues. These requirements will be, in some capacity, dependent on the platform that you've decided to use. They are as follows:

  • Unity 2020.3.26f1 or higher.
  • If you're using iOS:
    • Xcode 14.1 or higher.
    • CocoaPods 1.12.1 or higher.
    • iOS 14 or higher.
  • If you're using Android:
    • Minimum API level 23 or higher.
    • Targets API level 33 or higher.
    • Java SDK version 11.

Setting up the Particle dashboard

Once you've ensured that your project meets the above prerequisites, you'll also need three key values from the Particle dashboard: your projectId, clientKey, and appId. These directly connect your Unity project with the Particle dashboard, enabling customization, analytics, tracking, etc. To retrieve these, you'll need to head into the dashboard and create a new project, then a new application, as shown below:

  1. Sign up/log in to the Particle dashboard.

  1. Create a new project or enter an existing one.

  1. Create a new application, or skip this step if you already have one.

  1. Retrieve the project ID (projectId), the client key (clientKey), and the application ID (appId).

‎‎

‎‎

‎‎

‎‎

Configuration

With these values retrieved, you can move on to initial configuration and dependency management. This will vary in complexity depending on the platform used. To begin, for both iOS and Android, you'll need to download and install the Particle Unity package; this will include the necessary files for both Particle Connect and Particle Auth.

Head over to the particle-unity GitHub repository, and download the latest release (.unitypackage), then import this into your project.

iOS configuration

If you're building a Unity game on iOS, you must follow a specific configuration process to ensure that Particle Connect functions. The first step within this process is to set up a scheme URL within the Unity editor.

  1. Head into the iOS Player Settings menu (Edit -> Project Settings -> Player Settings -> iOS).
  2. From here, select Other, then scroll down to Configuration.
  3. Open the Supported URL schemes section, and within the Element 0 field, paste in your projectId with a prefix of pn.
    1. For example, if your projectId (from the Particle dashboard) is something like 63bfa427-cf5f-4742-9ff1-e8f5a1b9828f, then the scheme URL, in this case, would be pn63bfa427-cf5f-4742-9ff1-e8f5a1b9828f

📘

Remove other services, if needed

Within ParticleNetworkIOSBridge.cs, you'll have a number of services included in the SDK:

  • ParticleNetworkBase - required, universally.
  • ParticleAuthService - only if you're using Particle Auth directly, independently from Particle Connect.
  • ParticleWalletGUI - usage of the Particle Wallet UI, contains all services.
  • ParticleConnect - for Particle Connect.
  • ParticleAuthCore - only if you're using Particle Auth Core directly, independently from Particle Connect.

‎‎

You'll also need to configure your Podfile if you haven't already. If you don't have a Podfile, go to the root of your project directory and run pod init, this will generate a Podfile

Open this Podfile, and insert the specific pods (services) you'd like to use within your project. In this case, ParticleConnect and CommonConnect will generally suffice, but additional services can be added if needed.

Additionally, you'll need to paste in the below code snippet for installation handling:

pod 'ParticleWalletGUI'
// If you're using this, also include:
// pod 'SkeletonView', :git => 'https://github.com/SunZhiC/SkeletonView.git', :branch => 'main'

pod 'ParticleAuthService'
// Only needed if you're using Particle Auth directly; ParticleConnect includes Particle Auth

pod 'ParticleConnect'
pod 'CommonConnect'

// Paste this
post_install do |installer|
installer.pods_project.targets.each do |target|
  target.build_configurations.each do |config|
  config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
    end
  end
 end

With your Podfile set, you'll need to run pod install and open your .xcworkspace file, as shown below:

pod install --repo-update

open {your project}.xcworkspace

‎‎

Finally, for iOS, you'll need to formally use the projectId, clientKey, and appId previously retrieved. To do this, head into the root of your Xcode project and create a file, ParticleNetwork-Info.plist. Within this file, paste the following text (then replace the placeholders):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>PROJECT_UUID</key>
	<string>YOUR_PROJECT_UUID</string>
	<key>PROJECT_CLIENT_KEY</key>
	<string>YOUR_PROJECT_CLIENT_KEY</string>
	<key>PROJECT_APP_UUID</key>
	<string>YOUR_PROJECT_APP_UUID</string>
</dict>
</plist>

‎‎

Android configuration

If you're building your Unity game for Android, you'll just need to configure two files before you're ready to go. The first of these two files can be found at Assets/Plugins/Android/launcherTemplate.gradle within your project. Here, you'll need to ensure you have the necessary dependencies included.

Specifically, you'll need the following dependencies at a minimum:

  • network.particle:auth-serviceif you're planning on using Particle Auth directly.
  • network.particle:connect, required for Particle Connect.
  • network.particle:unity-bridge, required universally.
  • Additional dependencies, optional:
    • network.particle:chains, collection of chainInfo objects.
    • network.particle:connect-solana-adapter, Solana-specific custom wallet adapter to be used within Particle Connect.
    • network.particle:connect-phantom-adapter, Wallet adapter for Phantom to be used within Particle Connect.
    • network.particle:connect-evm-adapter, EVM-specific custom wallet adapter to be used within Particle Connect.
    • network.particle:connect-auth-adapter, Particle Auth adapter for Particle Connect (social logins).
    • network.particle:connect-wallet-connect-adapter, WalletConnect adapter for Particle Connect.
      The full list of network.particle packages can be found here.
dependencies {
    implementation project(':unityLibrary') 
    implementation "network.particle:auth-service:${sdkVersion}"
    implementation "network.particle:unity-bridge:${sdkVersion}"
  	implementation "network.particle:connect:${sdkVersion}"
  	// Other dependencies
}

‎‎

Finally, for Android, you'll need to place your projectId, clientKey, and appId within gradleTemplate.properties, found at Assets/Plugins/Android/gradleTemplate.properties.

particle.network.project_client_key=Your Client Key
particle.network.project_id=Your Project ID
particle.network.app_id=Your App ID

Initialization

Now that you've managed the relevant dependencies and configured your Unity environment, you'll need to initialize ParticleNetwork and ParticleConnectInteraction (both derived from Network.Particle.Scripts.Core) before moving on. This is required for Particle Connect to function.

ParticleNetwork can be initialized by simply calling Init and passing in a chainInfo object (*). ParticleConnectInteraction.Init will require both a chainInfo object and a DAppMetaData parameter (in this example, represented as metadata) containing a WalletConnect project ID retrieved from the WalletConnect dashboard, alongside the name of your project, the icon (preferably 512x512), the website URL, and a project description.

Additionally, with WalletConnect as the underlying infrastructure for Web3 wallets within Particle Connect, you'll also have the opportunity to include configuration for multiple different chains on WalletConnect by calling ParticleConnectInteraction.SetWalletConnectV2SupportChainInfos and passing in an array of chainInfo objects.

An example of the above process can be found below.

var metadata = new DAppMetaData(TestConfig.walletConnectProjectId,"Particle Connect",
            "https://connect.particle.network/icons/512.png",
            "https://connect.particle.network",
            "");

ParticleNetwork.Init(_chainInfo);
ParticleConnectInteraction.Init(_chainInfo, metadata);

List<ChainInfo> chainInfos = new List<ChainInfo>{new EthereumChain(EthereumChainId.Mainnet), new EthereumChain(EthereumChainId.Goerli), new EthereumChain(EthereumChainId.Sepolia)};
ParticleConnectInteraction.SetWalletConnectV2SupportChainInfos(chainInfos.ToArray());

Examples of Utilization

Set Chain Info

Before a user has connected, if you'd like to set the primary chain after initialization through .Init, you can call ParticleConnectInteraction.SetChainInfo, passing in a corresponding chainInfo object for the chain you'd like to switch to. Alternatively, SetChainInfoAsync can also be called after a user has connected to switch chains. E.g:

ParticleConnectInteraction.SetChainInfo(_chainInfo);

// Alternatively, post-connect
await ParticleConnect.Instance.SetChainInfoAsync(_chainInfo);

Connect Wallet

Within implementations of Particle Connect, Connect drives connection with a wallet in the Particle Connect stack, (social login or otherwise.) This is done through ParticleConnect.Instance.Connect, then passing in a relevant WalletType object, derived from Network.Particle.Scripts.Model

WalletType is an enum containing the following choices:

  • Particle, social logins through Particle Auth.
  • AuthCore, Particle Auth Core, an alternative to Particle Auth (Particle).
  • EvmPrivateKey, custom EVM wallet imports/exports.
  • SolanaPrivateKey, custom Solana wallet imports/exports.
  • MetaMask.
  • Rainbow.
  • Trust.
  • ImToken.
  • BitKeep.
  • WalletConnect.
  • Phantom, intended for Solana.
  • Zerion.
  • Math.
  • Inch1, 1inch.
  • Zengo.
  • Alpha.
  • OKX.
  • TokenPocket, not supported by iOS.

If you're using Particle, you'll also need to pass in a ConnectConfig object containing:

  • LoginType, the specific login to be prompted, is an enum with the following choices:
    • EMAIL.
    • PHONE.
    • FACEBOOK.
    • APPLE.
    • TWITTER.
    • DISCORD.
    • GITHUB.
    • TWITCH.
    • MICROSOFT.
    • LINKEDIN.
    • JWT.
  • account, if you're expecting a specific JWT, email, or phone (required for JWT).
  • SupportAuthType, the different authentication types to be supported by the popup modal.
    • enum with all of the above choices for LoginType, except JWT , including ALL.
  • SocialLoginPrompt, whether or not the social login popup will be in "form mode" (simplified, minimal UI) or not. By default, set to false.
  • LoginAuthorization, a string (hex for EVM, base58 for Solana) to be prompted for signature upon login as authorization. Optional.

E.g.:

await ParticleConnect.Instance.Connect(this._walletType);

ConnectConfig config = new ConnectConfig(LoginType.PHONE, null, SupportAuthType.ALL, false);
await ParticleConnect.Instance.Connect(WalletType.Particle, config);

Disconnect Wallet

To disconnect an active session, identified by a specific address, you can call ParticleConnect.Instance.Disconnect, passing in the specific wallet type (WalletType object) and associated address that you'd like to disconnect from your application, as is shown below.

await ParticleConnect.Instance.Disconnect(this._walletType, publicAddress);

Is Connected

Another important method is IsConnected, returning a Boolean indicating whether or not a user (or, in this case, an address and WalletType) are currently connected to your application. This can be called through ParticleConnectInteraction.IsConnected. E.g.:

ParticleConnectInteraction.IsConnected(this._walletType, publicAddress);

Sign and Send Transaction

ParticleConnect.Instance.SignAndSendTransaction acts as the primary mechanism for both EVM and Solana for sending (or, in this case, suggesting) transactions. Upon calling, the WalletType (the adapter in question) will return a confirmation popup requesting a signature from the user before sending the transaction directly to the network. SignAndSendTransaction takes three parameters:

  • WalletType, the type of wallet being used.
  • address, the public address being used.
  • transaction, a stringified representation of a transaction object.

E.g.:

await ParticleConnect.Instance.SignAndSendTransaction(this._walletType, publicAddress, transaction);

Sign Transaction

ParticleConnect.Instance.SignTransaction is a Solana-specific method for signing a transaction without pushing it to the network. This will behave similarly to SignAndSendTransaction, although it will only function on either the Phantom or SolanaPrivateKey wallet types and will purely return a signature.

The plural of this method is ParticleConnect.Instance.SignAllTransactions, taking a list of transactions to be prompted for signature, rather than just one.

await ParticleConnect.Instance.SignTransaction(this._walletType, publicAddress, transaction);

// Alternatively
await ParticleConnect.Instance.SignAllTransactions(this._walletType, publicAddress, transactions);

Sign Message

A simple message (UTF-8 string) can be signed on both EVM & Solana through ParticleConnect.Instance.SignMessage, passing in the WalletType, address (publicAddress in this example), and the message in question. message should be a general string to be signed. E.g.:

var message = "GM, Particle!";
await ParticleConnect.Instance.SignMessage(this._walletType, publicAddress, message);

Sign Typed Data

As an alternative to SignMessage, for EVM chains, you can request that a user signs typed (structured) data rather than purely a raw string. To do this, you can use adapter.signTypedData (equivalent to eth_signTypedData, represented as either TypedDataV4, TypedDataV2, or TypedDataV1). This takes the following parameters:

  • address, the user address to target for signature initiation.
  • data, the typed data to be signed; see the Web (JavaScript/TypeScript) page for additional guidance.

E.g.:

var txtAsset = Resources.Load<TextAsset>("TypedDataV4");
string typedData = txtAsset.text;

await ParticleConnect.Instance.SignTypedData(this._walletType, publicAddress, typedData);

Import Wallet

If you're using theEvmPrivateKey or SolanaPrivateKey wallet types, you can import wallets through either a seed phrase or private key. These methods will associate an account instance derived from these keys, allowing utilization within your application. These can be achieved through either ImportWalletFromPrivateKey for importing a private key, or ImportWalletFromMnemonic for importing a mnemonic (seed phrase). Both of these methods require both the WalletType (either EvmPrivateKey or SolanaPrivateKey) and the private key/seed phrase to be imported.

Additionally, you can export one of these wallets with ParticleConnect.Instance.ExportWalletPrivateKey, passing in the address (of the EvmPrivateKey or SolanaPrivateKey imported/generated wallet) that you'd like to export.

await ParticleConnect.Instance.ImportWalletFromPrivateKey(this._walletType, privateKey);
  
await ParticleConnect.Instance.ImportWalletFromMnemonic(this._walletType, mnemonic);

// Exportation
await ParticleConnect.Instance.ExportWalletPrivateKey(this._walletType, publicAddress);

Master reference

For a direct, raw view into every method provided through ParticleConnect and ParticleConnectInteraction, below is a table containing every relevant one, along with specific parameters and a short description. For methods listed that weren't covered in the above examples, live implementation often mimics the common structure covered throughout this document.

ClassMethodsParameters (* indicates optional)
ParticleConnectConnectwalletType, config*
ParticleConnectDisconnectwalletType, publicAddress
ParticleConnectSignMessagewalletType, publicAddress, message
ParticleConnectSignTransactionwalletType, publicAddress, transaction
ParticleConnectSignAllTransactionswalletType, publicAddress, transactions
ParticleConnectBatchSendTransactionswalletType, publicAddress, transactions, feeMode*
ParticleConnectSignAndSendTransactionwalletType, publicAddress, transaction, feeMode*
ParticleConnectSignTypedDatawalletType, publicAddress, typedData
ParticleConnectLoginwalletType, publicAddress, domain, uri
ParticleConnectVerifywalletType, publicAddress, message, signature
ParticleConnectImportWalletFromPrivateKeywalletType, privateKey
ParticleConnectImportWalletFromMnemonicwalletType, mnemonic
ParticleConnectExportWalletPrivateKeywalletType, publicAddress
ParticleConnectInteractionInitchainInfo, dAppMetadata, rpcUrl*, env
ParticleConnectInteractionSetWalletConnectV2SupportChainInfoschainInfos
ParticleConnectInteractionConnectwalletType, config*
ParticleConnectInteractionDisconnectwalletType, publicAddress
ParticleConnectInteractionIsConnectedwalletType, publicAddress
ParticleConnectInteractionGetAccountswalletType
ParticleConnectInteractionSignMessagewalletType, publicAddress, message
ParticleConnectInteractionSignTransactionwalletType, publicAddress, transaction
ParticleConnectInteractionSignAllTransactionswalletType, publicAddress, transactions
ParticleConnectInteractionBatchSendTransactionswalletType, publicAddress, transactions, feeMode*
ParticleConnectInteractionSignAndSendTransactionwalletType, publicAddress, transaction, feeMode*
ParticleConnectInteractionSignTypedDatawalletType, publicAddress, message
ParticleConnectInteractionImportPrivateKeywalletType, privateKey
ParticleConnectInteractionImportMnemonicwalletType, mnemonic
ParticleConnectInteractionExportPrivateKeywalletType, publicAddress
ParticleConnectInteractionLoginwalletType, publicAddress, domain, uri
ParticleConnectInteractionVerifywalletType, publicAddress, message, signature
ParticleConnectInteractionGetWalletReadyStatewalletType