Skip to content

Sign messages

Prerequisites

Before implementing message signing:

  • Ensure Openfort's embeddedState is ready
  • Verify the user is properly authenticated
  • Have an embedded wallet configured

Methods

SignMessage

Signs a plain text message using the EIP-191 personal_sign standard.

Method Signature:
public async UniTask<string> SignMessage(SignMessageRequest request)
Parameters:
  • SignMessageRequest request - The message signing request containing the message to sign
Returns:
  • UniTask<string> - The signature as a hex string
SignMessageRequest Structure:
public class SignMessageRequest
{
    public string Message { get; set; }
    
    public SignMessageRequest(string message)
    {
        Message = message;
    }
}
Example:
using System;
using UnityEngine;
using Cysharp.Threading.Tasks;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
 
public class BasicMessageSigner : MonoBehaviour
{
    private OpenfortSDK openfort;
    
    private async void Start()
    {
        // Initialize SDK
        openfort = await OpenfortSDK.Init(
            "YOUR_OPENFORT_PUBLISHABLE_KEY",
            "YOUR_SHIELD_PUBLISHABLE_KEY"
        );
    }
    
    public async UniTask<string> SignTextMessage(string message)
    {
        try
        {
            // Check if wallet is ready
            var state = await openfort.GetEmbeddedState();
            if (state != EmbeddedState.READY)
            {
                throw new InvalidOperationException(quot;Wallet not ready. State: {state}");
            }
            
            // Create request and sign
            var request = new SignMessageRequest(message);
            var signature = await openfort.SignMessage(request);
            
            Debug.Log(quot;Message '{message}' signed successfully");
            Debug.Log(quot;Signature: {signature}");
            
            return signature;
        }
        catch (Exception e)
        {
            Debug.LogError(quot;Failed to sign message: {e.Message}");
            throw;
        }
    }
    
    // Example usage
    public async UniTaskVoid SignWelcomeMessage()
    {
        string welcomeMsg = "Welcome to My Game!";
        await SignTextMessage(welcomeMsg);
    }
}

SignTypedData

Signs structured data using the EIP-712 eth_signTypedData_v4 standard.

Method Signature:
public async UniTask<string> SignTypedData(SignTypedDataRequest request)
Parameters:
  • SignTypedDataRequest request - The typed data signing request
Returns:
  • UniTask<string> - The signature as a hex string
SignTypedDataRequest Structure:
public class SignTypedDataRequest
{
    public Dictionary<string, object> Domain { get; set; }
    public Dictionary<string, object[]> Types { get; set; }
    public Dictionary<string, object> Value { get; set; }
    
    public SignTypedDataRequest(
        Dictionary<string, object> domain, 
        Dictionary<string, object[]> types, 
        Dictionary<string, object> value)
    {
        Domain = domain;
        Types = types;
        Value = value;
    }
}
Example:
using System;
using System.Collections.Generic;
using UnityEngine;
using Cysharp.Threading.Tasks;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
 
public class TypedDataSigner : MonoBehaviour
{
    private OpenfortSDK openfort;
    
    private async void Start()
    {
        openfort = await OpenfortSDK.Init(
            "YOUR_OPENFORT_PUBLISHABLE_KEY", 
            "YOUR_SHIELD_PUBLISHABLE_KEY"
        );
    }
    
    public async UniTask<string> SignPlayerScore(string playerName, int score, string contractAddress)
    {
        try
        {
            // Check wallet state
            var state = await openfort.GetEmbeddedState();
            if (state != EmbeddedState.READY)
            {
                throw new InvalidOperationException(quot;Wallet not ready. State: {state}");
            }
            
            // Define the domain
            var domain = new Dictionary<string, object>
            {
                { "name", "GameLeaderboard" },
                { "version", "1" },
                { "chainId", 80002 },
                { "verifyingContract", contractAddress }
            };
            
            // Define the types
            var types = new Dictionary<string, object[]>
            {
                {
                    "ScoreEntry", new object[]
                    {
                        new Dictionary<string, object> { { "name", "player" }, { "type", "string" } },
                        new Dictionary<string, object> { { "name", "score" }, { "type", "uint256" } },
                        new Dictionary<string, object> { { "name", "timestamp" }, { "type", "uint256" } }
                    }
                }
            };
            
            // Define the value
            var value = new Dictionary<string, object>
            {
                { "player", playerName },
                { "score", score },
                { "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
            };
            
            // Create request and sign
            var request = new SignTypedDataRequest(domain, types, value);
            var signature = await openfort.SignTypedData(request);
            
            Debug.Log(quot;Score entry signed for {playerName}: {score}");
            return signature;
        }
        catch (Exception e)
        {
            Debug.LogError(quot;Failed to sign typed data: {e.Message}");
            throw;
        }
    }
}

Complete Example

Here's a comprehensive example combining both message types:

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
 
public class MessageSigningDemo : MonoBehaviour
{
    private OpenfortSDK openfort;
    
    [Header("UI References")]
    [SerializeField] private Button signMessageButton;
    [SerializeField] private Button signTypedDataButton;
    [SerializeField] private TMPro.TMP_InputField messageInput;
    [SerializeField] private TMPro.TextMeshProUGUI signatureOutput;
    
    private async void Start()
    {
        // Initialize SDK
        openfort = await OpenfortSDK.Init(
            "YOUR_OPENFORT_PUBLISHABLE_KEY",
            "YOUR_SHIELD_PUBLISHABLE_KEY"
        );
        
        // Setup UI
        signMessageButton.onClick.AddListener(() => SignUserMessage().Forget());
        signTypedDataButton.onClick.AddListener(() => SignGameData().Forget());
    }
    
    private async UniTaskVoid SignUserMessage()
    {
        try
        {
            await WaitForWalletReady();
            
            string message = messageInput.text;
            if (string.IsNullOrEmpty(message))
                message = "Hello from Unity!";
            
            var request = new SignMessageRequest(message);
            var signature = await openfort.SignMessage(request);
            
            signatureOutput.text = quot;Signature: {signature.Substring(0, 20)}...";
        }
        catch (Exception e)
        {
            signatureOutput.text = quot;Error: {e.Message}";
        }
    }
    
    private async UniTaskVoid SignGameData()
    {
        try
        {
            await WaitForWalletReady();
            
            // Example game data
            var domain = new Dictionary<string, object>
            {
                { "name", "Unity Game" },
                { "version", "1" },
                { "chainId", 80002 }
            };
            
            var types = new Dictionary<string, object[]>
            {
                {
                    "GameData", new object[]
                    {
                        new Dictionary<string, object> { { "name", "level" }, { "type", "uint256" } },
                        new Dictionary<string, object> { { "name", "player" }, { "type", "string" } }
                    }
                }
            };
            
            var value = new Dictionary<string, object>
            {
                { "level", 5 },
                { "player", "TestPlayer" }
            };
            
            var request = new SignTypedDataRequest(domain, types, value);
            var signature = await openfort.SignTypedData(request);
            
            signatureOutput.text = quot;Typed signature: {signature.Substring(0, 20)}...";
        }
        catch (Exception e)
        {
            signatureOutput.text = quot;Error: {e.Message}";
        }
    }
    
    private async UniTask WaitForWalletReady()
    {
        while (true)
        {
            var state = await openfort.GetEmbeddedState();
            if (state == EmbeddedState.READY) return;
            await UniTask.Delay(100);
        }
    }
}

Examples

Unity Sample Android Embedded Wallet

An integration with Google Play Games using Firebase Auth as a third party auth provider to create a non-custodial embedded wallet.

Unity Sample WebGL Embedded Wallet

An integration with Openfort Auth with non-custodial embedded wallet.