Azure PlayFab (NodeJS) with Unity
This tutorial will teach you how to set up a complete gaming backend platform for Web3 games. We use Unity as our game engine, Microsoft Azure PlayFab as our gaming backend, and Moralis to enable all the Web3 magic! You'll also learn how to use Web3 authentication and how to retrieve a user's native balance, a list of ERC-20 tokens, and the first ten NFTs they own using the Web3 API.
The Steps We Will Take
- Set up a Moralis account
- Set up Microsoft Azure PlayFab (free plan)
- Set up Azure Functions
- Create Azure Functions with Visual Studio Code
- Deploy Azure Functions with Visual Studio Code
- Set up Unity and connect Microsoft Azure PlayFab
Set up a Moralis Account
This section describes how to set up your Moralis account and find the Web3 API you need to integrate. Your Moralis account provides access to all Moralis Web3 functionality.
- Create a Moralis account if you don't already have one.
- Go to Web3 APIs and copy and save the API key v3. You will need this when setting up Azure Functions.
Set up Microsoft Azure PlayFab (free plan)
An active PlayFab account is required to use the functionality provided by PlayFab. Please note that a free plan is available. This section describes how to set up a PlayFab account and configure your first application.
PlayFab is a complete backend platform for live games with managed game services. PlayFab backend services reduce the barriers to launch for game developers, offering both large and small studios cost-effective development solutions that scale with their games and help them engage, retain, and monetize players. PlayFab enables developers to use the intelligent cloud to build and operate games, analyze gaming data, and improve overall gaming experiences. Learn more
- Create a PlayFab Account.
- Create a new title on PlayFab:
- Open your new title and go to Title settings:
- Go to the API Features tab and write down the Title ID. You will need this when setting up Azure Functions.
- Go to the Secret Keys tab and write down the secret key. You will need this when setting up Azure Functions.
Set up Azure Functions
To run Moralis on the backend of PlayFab, we need to use Azure Functions. Azure Functions integrates natively with PlayFab; however, Azure Functions is a separate product and requires an account separate from PlayFab.
Azure Functions provides serverless compute. You can use Azure Functions to build web APIs, respond to database changes, process IoT streams, manage message queues, and more. PlayFab uses Azure Functions to make it possible to use Moralis on top of the PlayFab backend. More info
- Create a free Azure account.
- Create a Microsoft Customer Agreement subscription.
- Search for Function App and select it.
- Create a new Function App:
- Select Review + create and then Create.
- Open the MoralisAzureFunctions resource:
- Go to Configuration and select New application setting:
- Create a new application setting and enter MORALIS_API_KEY as the name, and in the value, paste your Moralis API key. Leave Deployment slot setting unchecked and select Ok.
- Create another application setting and enter PLAYFAB_TITLE_ID as the name, and in the value, paste your PlayFab title ID. Leave Deployment slot setting unchecked and select Ok.
- Create another application setting and enter PLAYFAB_DEV_SECRET_KEY as the name, and in the value, paste your PlayFab secret key. Leave Deployment slot setting unchecked and select Ok.
- Select Save and then Continue.
Create Azure Functions with Visual Studio Code
This section walks through coding functions that integrate the Moralis SDK.
Make sure you have the following requirements in place:
- Visual Studio Code
- Azure Functions extension for Visual Studio Code
Prerequisites
Function creation
The completed project with all the functions ready can be found on GitHub. Download it, open it with VS Code and jump to Installing dependencies to complete this section. However, continue exploring the section to learn how to do it yourself.
Authentication API functions
Create ChallengeRequest
function
- Open Visual Studio Code.
- Select Azure and sign in.
- Under Workspace select Create Function:
- Select Create new project and create an empty folder. I named mine example-auth-azure-functions-nodejs:
- For the language select Javascript:
- Select HTTP Trigger for the template:
- Name it ChallengeRequest and press Enter:
- Select Function for the authorization level:
- Finally, select Open in current window:
- We now have the
ChallengeRequest
function created:
- Replace the existing code in index.js for this:
const Moralis = require('moralis').default;
const ApiKey = process.env.MORALIS_API_KEY;
const NETWORK = 'evm'; // We assume it's we are using an EVM-compatible chain
const DOMAIN = 'moralis.io';
const STATEMENT = 'Please sign this message to confirm your identity.';
const URI = 'https://moralis.io/';
const EXPIRATION_TIME = '2023-01-01T00:00:00.000Z';
const TIMEOUT = 15;
Moralis.start({
apiKey: ApiKey
})
module.exports = async function (context, req) {
try {
if (!req.body) {
context.res = {
status: 400,
body: "Please pass a request body",
};
}
const result = await Moralis.Auth.requestMessage({
address: req.body.FunctionArgument.address,
chain: req.body.FunctionArgument.chainid,
network: NETWORK,
domain: DOMAIN,
statement: STATEMENT,
uri: URI,
expirationTime: EXPIRATION_TIME,
timeout: TIMEOUT,
})
context.res = {
body: result.raw.message // We just want to return the message
};
} catch (error) {
console.log(error);
context.res = {
status: 500,
body: JSON.stringify(error)
}
}
}
As we can see at the top, we get the MORALIS_API_KEY
from the environment (we set it up in Azure Functions), we set some constants we'll need later and we start Moralis using the key:
const Moralis = require('moralis').default;
const ApiKey = process.env.MORALIS_API_KEY;
const NETWORK = 'evm'; // We assume it's we are using an EVM-compatible chain
const DOMAIN = 'moralis.io';
const STATEMENT = 'Please sign this message to confirm your identity.';
const URI = 'https://moralis.io/';
const EXPIRATION_TIME = '2023-01-01T00:00:00.000Z';
const TIMEOUT = 15;
Moralis.start({
apiKey: ApiKey
})
Then, inside module.exports
we call Moralis.Auth.requestMessage()
passing the constants that we set on top and we get the address
and the chain
from the request body. This will return a message as a result:
module.exports = async function (context, req) {
try {
if (!req.body) {
context.res = {
status: 400,
body: "Please pass a request body",
};
}
const result = await Moralis.Auth.requestMessage({
address: req.body.FunctionArgument.address,
chain: req.body.FunctionArgument.chainid,
network: NETWORK,
domain: DOMAIN,
statement: STATEMENT,
uri: URI,
expirationTime: EXPIRATION_TIME,
timeout: TIMEOUT,
})
context.res = {
body: result.raw.message // We just want to return the message
};
} catch (error) {
console.log(error);
context.res = {
status: 500,
body: JSON.stringify(error)
}
}
}
To summarize, to call this ChallengeRequest
function we will need a POST request containing the wallet address and the chain id as arguments, but we'll see that later in the tutorial.
For now we need to create another function that will verify the message resulting of this one.
Create ChallengeVerify
function
- Repeat the same steps as for
ChallengeRequest
(no need to create a new project now) but this time name itChallengeVerify
:
- Replace the existing code in
index.js
for this:
const Moralis = require('moralis').default;
var PlayFab = require("playfab-sdk/Scripts/PlayFab/PlayFab.js");
var PlayFabServer = require("playfab-sdk/Scripts/PlayFab/PlayFabServer.js");
const PlayFabTitleId = process.env.PLAYFAB_TITLE_ID
const PlayFabDeveloperKey = process.env.PLAYFAB_DEV_SECRET_KEY
const NETWORK = 'evm'; // We assume it's we are using an EVM-compatible chain
module.exports = async function (context, req) {
try {
if (!req.body) {
context.res = {
status: 400,
body: "Please pass a request body",
};
}
const verifiedData = await Moralis.Auth.verify({
message: req.body.FunctionArgument.message,
signature: req.body.FunctionArgument.signature,
network: NETWORK,
})
// When do we consider that the authentication is completed? Before or After updating user data in PlayFab??
// Maybe here we should already return if the data has been verified or not.
context.res = {
body: verifiedData.raw
};
//TODO Set PlayFab player data with some of the verified data!
PlayFab.settings.titleId = PlayFabTitleId;
PlayFab.settings.developerSecretKey = PlayFabDeveloperKey;
// Preparing request
var updateUserDataRequest = {
PlayFabId: req.body.CallerEntityProfile.Lineage.MasterPlayerAccountId,
Data: {
"MoralisProfileId": verifiedData.raw.id,
"Address": verifiedData.raw.address,
"ChainId": verifiedData.raw.chainId
}
}
PlayFabServer.UpdateUserReadOnlyData(
updateUserDataRequest,
(error, result) => {
if (result !== null) {
context.log("API call was successful.");
context.res = {
status: 200,
body: result
};
context.done();
} else if (error !== null) {
context.log("Something went wrong with the API call.");
context.res = {
status: 500,
body: JSON.stringify(error)
};
context.done();
}
}
)
} catch (error) {
context.log(error);
context.res = {
status: 500,
body: JSON.stringify(error)
}
}
}
As we see at the top, in this function we need the PlayFab SDK besides Moralis (we will install both later). Then we get the PlayFab environment variables that we set in Azure Functions and we set the NETWORK
:
const Moralis = require('moralis').default;
var PlayFab = require("playfab-sdk/Scripts/PlayFab/PlayFab.js");
var PlayFabServer = require("playfab-sdk/Scripts/PlayFab/PlayFabServer.js");
const PlayFabTitleId = process.env.PLAYFAB_TITLE_ID
const PlayFabDeveloperKey = process.env.PLAYFAB_DEV_SECRET_KEY
const NETWORK = 'evm'; // We assume it's we are using an EVM-compatible chain
Inside module.exports
we call Moralis.Auth.verify()
, receiving the message
and the signature
from the request body:
const verifiedData = await Moralis.Auth.verify({
message: req.body.FunctionArgument.message,
signature: req.body.FunctionArgument.signature,
network: NETWORK,
})
// When do we consider that the authentication is completed? Before or After updating user data in PlayFab??
// Maybe here we should already return if the data has been verified or not.
context.res = {
body: verifiedData.raw
};
NFT API functions
Create GetWalletNfts
function
Repeat the same steps as before to create the new function but name it accordingly. Once created, copy the following code into index.js
:
const Moralis = require('moralis').default;
const ApiKey = process.env.MORALIS_API_KEY;
Moralis.start({
apiKey: ApiKey
})
module.exports = async function (context, req) {
try {
if (!req.body) {
context.res = {
status: 400,
body: "Please pass a request body",
};
}
const response = await Moralis.EvmApi.nft.getWalletNFTs({
address: req.body.FunctionArgument.walletAddress,
chain: req.body.FunctionArgument.chainid
});
context.res = {
body: response
};
} catch (error) {
console.log(error);
context.res = {
status: 500,
body: JSON.stringify(error)
}
}
}
For this function we only need the walletAddress
and the chainid
in the request body. You can take a look on how to do this on Unity.
EVM API functions
Create RunContractFunction
function
Repeat the same steps as before to create the new function but name it accordingly. Once created, copy the following code into index.js
:
const Moralis = require('moralis').default;
const ApiKey = process.env.MORALIS_API_KEY;
Moralis.start({
apiKey: ApiKey
})
module.exports = async function (context, req) {
try {
if (!req.body) {
context.res = {
status: 400,
body: "Please pass a request body",
};
}
const abi = JSON.parse(req.body.FunctionArgument.functionAbi);
const params = JSON.parse(req.body.FunctionArgument.functionParams);
const response = await Moralis.EvmApi.utils.runContractFunction({
abi,
functionName: req.body.FunctionArgument.functionName,
address: req.body.FunctionArgument.contractAddress,
chain: req.body.FunctionArgument.chainid,
params
});
context.res = {
body: response.result
};
} catch (error) {
console.log(error);
context.res = {
status: 500,
body: JSON.stringify(error)
}
}
}
For this one we'll need to pass various parameters in the request body, related to the contract that we want to run the function from. You can see an example on how to set the parameters in a Unity method and how to call it.
Installing dependencies
- Open the terminal in VS Code:
- Install the Moralis JS SDK and the PlayFab SDK by running this command:
npm install moralis playfab-sdk
Deploy Azure Functions with Visual Studio Code
This section walks through deploying Azure Functions.
- Sign in to Azure:
- Right-click on MoralisAzureFunctionsJS and select Deploy to Function App:
- Select Deploy:
- Go to your PlayFab title ID dashboard and go to Automation:
- Select Register function and set the Trigger type to HTTP. Enter ChallengeRequest as the function name and copy the function URL from Visual Studio Code. Right-click on ChallengeRequest under Functions and select Copy Function Url, and paste it into the Function URL field. Select Register function.
- Create another Register function and set the Trigger type to HTTP. Enter ChallengeVerify as the function name and copy the function URL from Visual Studio Code. Right-click on ChallengeVerify under Functions and select Copy Function Url, and paste it into the Function URL field. Select Register function.
- If you want, repeat step #6 above for all the other functions we added.
Set up Unity and Connect Microsoft Azure PlayFab
This section describes how to set up a Unity application and connect to PlayFab and enable secure Web3 authentication using the Moralis SDK.
Currently this sample project only showcase how to call the Authentication API functions. To see how to call other functions implemented in this guide (like NFT or EVM related), check this more advanced project.
- Download as ZIP and extract the Moralis PlayFab Unity demo project:
- Open the project in Unity (recommend version: 2021.3.10f1).
- Open PlayFab Editor Extensions (If the PlayFab menu doesn’t show this, restart Unity).
- Login with your email and password:
- Go to Settings > Project:
- Select your Studio and Title ID.
- Go to Scenes and open SampleScene:
Programmatically Interact with Moralis via PlayFab
If you choose the Starter project, this section will walk you through the code necessary to integrate with Moralis via PlayFab.
If you choose the Complete project, feel free to skip this section and play the game!.
Programmatically integrate with Moralis via PlayFab.
- In the Hierarchy view, right-click and select Create Empty. Name this object MoralisWeb3AuthService.
- In the Assets/Scripts folder view, create a new script called
MoralisWeb3AuthService.cs
:
- Drag and drop the
MoralisWeb3AuthService.cs
script into the MoralisWeb3AuthService object. - Open the edit the
MoralisWeb3AuthService.cs
script. - Remove the
Start
andUpdate
functions. - Update the
using
statements to include required PlayFab, WalletConnect, Unity, and Moralis resources. Like this:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using PlayFab;
using PlayFab.CloudScriptModels;
using WalletConnectSharp.Unity;
using Assets.Scripts.Moralis;
- Next, we want to be able to respond to two events that will be evoked by AuthenticationKit. These will show in our scene object. Add two Unity events,
OnSuccess
andOnFailed
. Also, add a reference to AuthenticationKit. YourMoralisWeb3AuthService.cs
should now look similar to this:
/// <summary>
/// Invoked when authentication was
///
[Header("Events")] public UnityEvent OnSuccess = new UnityEvent();
/// <summary>
/// Invoked when State==AuthenticationKitState.Disconnected
///
public UnityEvent OnFailed = new UnityEvent();
private AuthenticationKit authenticationKit = null;
- Add an
Awake
method that initializes theauthenticationKit
variable:
public void Awake()
{
authenticationKit = FindObjectOfType<AuthenticationKit>(true);
}
- Next, we will create a method to call the
ChallangeRequest
Azure Function via PlayFab. In theMoralisWeb3AuthService
class, create a private method calledCreateMessage
. This method should accept two parameters,address
(string) andchainid
(int), and returnvoid
. - To communicate with PlayFab, we will use the
ExecuteFunction
method of thePlayFabCloudScriptAPI
object provided by PlayFab. This function accepts three parameters, an ExecuteFunctionRequest object, a callback to handle a success response, and a callback to handle an error response. With these, yourCreateMessage
method should look similar to this:
private void CreateMessage(string address, int chainid)
{
// Get message from Moralis with PlayFab Azure Functions
PlayFabCloudScriptAPI.ExecuteFunction(new ExecuteFunctionRequest()
{
Entity = null, // Security information
FunctionName = null, //This should be the name of your Azure Function that you created.
FunctionParameter = null, //This is the data that you would want to pass into your function.
GeneratePlayStreamEvent = true //Set this to true if you would like this call to show up in PlayStream (logging)
}, async (ExecuteFunctionResult result) =>
{
}, (PlayFabError error) =>
{
});
}
- Set up the security information for the call. To do this, update the Entity property of
ExecuteFunctionRequest
to:
Entity = new PlayFab.CloudScriptModels.EntityKey()
{
Id = PlayFabSettings.staticPlayer.EntityId, // Get this from when you logged in,
Type = PlayFabSettings.staticPlayer.EntityType, // Get this from when you logged in
},
- Update the error callback parameter of
PlayFabCloudScriptAPI.ExecuteFunction
to invoke theOnFailed
Unity event:
(PlayFabError error) =>
{
Debug.Log($"Oops Something went wrong: {error.GenerateErrorReport()}");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
});
- Create a copy of the
CreateMessage
method and name itAuthenticate
. Change the parameters tomessage
(string) andsignature
(string). - In the
CreateMessage
method, find the FunctionName parameter ofExecuteFunctionRequest
and set this to "ChallengeRequest". This tells PlayFab which of the functions should be called. - In the
CreateMessage
method, find the FunctionParameter parameter of theExecuteFunctionRequest
and change it so that it passes in the two parameters supplied to theCreateMessage
method:
FunctionParameter =
new Dictionary<string, object>() //This is the data that you would want to pass into your function.
{
{ "address", address },
{ "chainid", chainid }
},
- In the success callback parameter, add a conditional statement that checks if a PlayFab limit exceeded condition exists; if it does, invoke
OnFailed
:
if (result.FunctionResultTooLarge ?? false)
{
Debug.Log(
"This can happen if you exceed the limit that can be returned from an Azure Function; see PlayFab Limits Page for details.");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
return;
}
- Still, within success callback, retrieve the result. If a result was returned, extract the message returned by Moralis and request the user to cryptographically sign it.
- If the user signs the message, call the
Authenticate
method, passing in the message and the resulting signature. If the signing of the message failed, invokeOnFailed
. The completeCreateMessage
method should look similar to this:
private void CreateMessage(string address, int chainid)
{
// Get message from Moralis with PlayFab Azure Functions
PlayFabCloudScriptAPI.ExecuteFunction(new ExecuteFunctionRequest()
{
Entity = new PlayFab.CloudScriptModels.EntityKey()
{
Id = PlayFabSettings.staticPlayer.EntityId, //Get this from when you logged in,
Type = PlayFabSettings.staticPlayer.EntityType, //Get this from when you logged in
},
FunctionName = "ChallengeRequest", //This should be the name of your Azure Function that you created.
FunctionParameter =
new Dictionary<string, object>() //This is the data that you would want to pass into your function.
{
{ "address", address },
{ "chainid", chainid }
},
GeneratePlayStreamEvent = true //Set this to true if you would like this call to show up in PlayStream
}, async (ExecuteFunctionResult result) =>
{
if (result.FunctionResultTooLarge ?? false)
{
Debug.Log(
"This can happen if you exceed the limit that can be returned from an Azure Function; see PlayFab Limits Page for details.");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
return;
}
// Check if we got a message
string message = result.FunctionResult.ToString();
if (!String.IsNullOrEmpty(message))
{
authenticationKit.State = AuthenticationKitState.WalletSigning;
#if !UNITY_WEBGL
// Sign the message with WalletConnect
string signature = await WalletConnect.ActiveSession.EthPersonalSign(address, message);
#else
// Sign the message with Web3
string signature = await Web3GL.Sign(message);
#endif
if (!String.IsNullOrEmpty(signature))
{
// Send the message and signature to the Authenticate Azure function for validation
Authenticate(message, signature);
}
else
{
// If there is no signature fire the OnFailed event
OnFailed.Invoke();
}
}
else
{
// If the is no message fire the OnFailed event
OnFailed.Invoke();
}
}, (PlayFabError error) =>
{
Debug.Log($"Oops Something went wrong: {error.GenerateErrorReport()}");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
});
}
- In the
Authenticate
method, find the FunctionName parameter of theExecuteFunctionRequest
and set this to "ChallengeVerify". This tells PlayFab which of the functions should be called. - In the
CreateMessage
method, find the FunctionParameter parameter of theExecuteFunctionRequest
and change it so that it passes in the two parameters supplied to theAuthenticate
method:
FunctionParameter =
new Dictionary<string, object>() //This is the data that you would want to pass into your function.
{
{ "message", message},
{ "signature", signature}
},
- In the success callback parameter, add a conditional statement that checks if a PlayFab limit exceeded condition exists; if it does, invoke
OnFailed
:
if (result.FunctionResultTooLarge ?? false)
{
Debug.Log(
"This can happen if you exceed the limit that can be returned from an Azure Function; see PlayFab Limits Page for details.");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
return;
}
- Now, check to see if the result is empty. If not, the verification call succeeded, invoke
OnSuccess
; otherwise, invokeOnFailed
. Your completeAuthenticate
method should look similar to this:
private void Authenticate(string message, string signature)
{
// Send the message and signature to the Authenticate Azure function for validation
PlayFabCloudScriptAPI.ExecuteFunction(new ExecuteFunctionRequest()
{
Entity = new PlayFab.CloudScriptModels.EntityKey()
{
Id = PlayFabSettings.staticPlayer.EntityId, //Get this from when you logged in,
Type = PlayFabSettings.staticPlayer.EntityType, //Get this from when you logged in
},
FunctionName = "ChallengeVerify", //This should be the name of your Azure Function that you created.
FunctionParameter =
new Dictionary<string, object>() //This is the data that you would want to pass into your function.
{
{ "message", message },
{ "signature", signature }
},
GeneratePlayStreamEvent = true //Set this to true if you would like this call to show up in PlayStream
}, (ExecuteFunctionResult result) =>
{
if (result.FunctionResultTooLarge ?? false)
{
Debug.Log(
"This can happen if you exceed the limit that can be returned from an Azure Function; see PlayFab Limits Page for details.");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
return;
}
// If the authentication succeeded, the user profile is updated and we get the UpdateUserDataAsync return values as response
// If it failed it returns empty
if (!String.IsNullOrEmpty(result.FunctionResult.ToString()))
{
authenticationKit.State = AuthenticationKitState.WalletSigned;
// On success fire the OnSuccess event
OnSuccess.Invoke();
}
else
{
// If the response is empty, fire the OnFailed event
OnFailed.Invoke();
}
}, (PlayFabError error) =>
{
Debug.Log($"Oops Something went wrong: {error.GenerateErrorReport()}");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
});
}
- The final step is to add a method that will be called when the authentication kit changes state. When the state changes to AuthenticationKitState.WalletConnected, we can extract the user's wallet address and chain ID to call the
CreateMessage
method. The code for this method is:
public void StateObservable_OnValueChanged(AuthenticationKitState authenticationKitState)
{
switch (authenticationKitState)
{
case AuthenticationKitState.WalletConnected:
#if !UNITY_WEBGL
// Get the address and chain ID with WalletConnect
string address = WalletConnect.ActiveSession.Accounts[0];
int chainid = WalletConnect.ActiveSession.ChainId;
#else
// Get the address and chain ID with Web3
string address = Web3GL.Account().ToLower();
int chainid = Web3GL.ChainId();
#endif
// Create sign message
CreateMessage(address, chainid);
break;
}
}
Your complete MoralisWeb3AuthService.cs
file should now look similar to this:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using PlayFab;
using PlayFab.CloudScriptModels;
using WalletConnectSharp.Unity;
using Assets.Scripts.Moralis;
public class MoralisWeb3AuthService : MonoBehaviour
{
// Events ----------------------------------------
/// <summary>
/// Invoked when authentication was
///
[Header("Events")] public UnityEvent OnSuccess = new UnityEvent();
/// <summary>
/// Invoked when State==AuthenticationKitState.Disconnected
///
public UnityEvent OnFailed = new UnityEvent();
private AuthenticationKit authenticationKit = null;
public void Awake()
{
authenticationKit = FindObjectOfType<AuthenticationKit>(true);
}
public void StateObservable_OnValueChanged(AuthenticationKitState authenticationKitState)
{
switch (authenticationKitState)
{
case AuthenticationKitState.WalletConnected:
#if !UNITY_WEBGL
// Get the address and chain ID with WalletConnect
string address = WalletConnect.ActiveSession.Accounts[0];
int chainid = WalletConnect.ActiveSession.ChainId;
#else
// Get the address and chain ID with Web3
string address = Web3GL.Account().ToLower();
int chainid = Web3GL.ChainId();
#endif
// Create sign message
CreateMessage(address, chainid);
break;
}
}
private void CreateMessage(string address, int chainid)
{
// Get message from Moralis with PlayFab Azure Functions
PlayFabCloudScriptAPI.ExecuteFunction(new ExecuteFunctionRequest()
{
Entity = new PlayFab.CloudScriptModels.EntityKey()
{
Id = PlayFabSettings.staticPlayer.EntityId, //Get this from when you logged in,
Type = PlayFabSettings.staticPlayer.EntityType, //Get this from when you logged in
},
FunctionName = "ChallengeRequest", //This should be the name of your Azure Function that you created.
FunctionParameter =
new Dictionary<string, object>() //This is the data that you would want to pass into your function.
{
{ "address", address },
{ "chainid", chainid }
},
GeneratePlayStreamEvent = true //Set this to true if you would like this call to show up in PlayStream
}, async (ExecuteFunctionResult result) =>
{
if (result.FunctionResultTooLarge ?? false)
{
Debug.Log(
"This can happen if you exceed the limit that can be returned from an Azure Function; see PlayFab Limits Page for details.");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
return;
}
// Check if we got a message
string message = result.FunctionResult.ToString();
if (!String.IsNullOrEmpty(message))
{
authenticationKit.State = AuthenticationKitState.WalletSigning;
#if !UNITY_WEBGL
// Sign the message with WalletConnect
string signature = await WalletConnect.ActiveSession.EthPersonalSign(address, message);
#else
// Sign the message with Web3
string signature = await Web3GL.Sign(message);
#endif
if (!String.IsNullOrEmpty(signature))
{
// Send the message and signature to the Authenticate Azure function for validation
Authenticate(message, signature);
}
else
{
// If there is no signature, fire the OnFailed event
OnFailed.Invoke();
}
}
else
{
// If there is no message, fire the OnFailed event
OnFailed.Invoke();
}
}, (PlayFabError error) =>
{
Debug.Log($"Oops Something went wrong: {error.GenerateErrorReport()}");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
});
}
private void Authenticate(string message, string signature)
{
// Send the message and signature to the Authenticate Azure function for validation
PlayFabCloudScriptAPI.ExecuteFunction(new ExecuteFunctionRequest()
{
Entity = new PlayFab.CloudScriptModels.EntityKey()
{
Id = PlayFabSettings.staticPlayer.EntityId, //Get this from when you logged in,
Type = PlayFabSettings.staticPlayer.EntityType, //Get this from when you logged in
},
FunctionName = "ChallengeVerify", //This should be the name of your Azure Function that you created.
FunctionParameter =
new Dictionary<string, object>() //This is the data that you would want to pass into your function.
{
{ "message", message },
{ "signature", signature }
},
GeneratePlayStreamEvent = true //Set this to true if you would like this call to show up in PlayStream
}, (ExecuteFunctionResult result) =>
{
if (result.FunctionResultTooLarge ?? false)
{
Debug.Log(
"This can happen if you exceed the limit that can be returned from an Azure Function; see PlayFab Limits Page for details.");
// If there is an error, fire the OnFailed event
OnFailed.Invoke();
return;
}
// If the authentication succeeded, the user profile is updated and we get the UpdateUserDataAsync return values as response
// If it fails it returns empty
if (!String.IsNullOrEmpty(result.FunctionResult.ToString()))
{
authenticationKit.State = AuthenticationKitState.WalletSigned;
// On success, fire the OnSuccess event
OnSuccess.Invoke();
}
else
{
// If the response is empty, fire the OnFailed event
OnFailed.Invoke();
}
}, (PlayFabError error) =>
{
Debug.Log($"Oops Something went wrong: {error.GenerateErrorReport()}");
// If the is a error fire the OnFailed event
OnFailed.Invoke();
});
}
}
Steps to Wire Up MoralisWeb3AuthService
- In the Unity UI, in the Hierarchy view, select the
MoralisWeb3AuthService
object and add entries under both On Success and On Failed. Drag AuthenticationKit into each of these, selecting AuthenticationKit/Connect for On Success and AuthenticationKit/Disconnect for On Failed:
- In the Unity UI, in the Hierarchy view, select the AuthenticationKit object. Add an entry to On State Changed (AuthenticationStateChanged). Drag the MoralisWeb3AuthService object to this entry and select MoralisWeb3AuthService/StateObservable_OnValueChanged:
Play the Game!
- Run the SampleScene and select PLAY AS GUEST:
- Select CONNECT WALLET:
- Select CONNECT and scan the QR code with your wallet and follow all the steps.
- If you return to the LOGGED IN screen, the wallet information is added to the player's profile under Players > Player Data:
- Celebrate your epic setup and start thinking of all the Web3 games you can now build!