# 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](https://docs.metamask.io/wallet/reference/personal_sign/) standard.

**Method Signature:**

```csharp
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:**

```csharp
public class SignMessageRequest
{
    public string message;            // Message to be signed
    public SignMessageOptions options; // Optional signing options

    public SignMessageRequest(string message, SignMessageOptions options = null)
    {
        this.message = message;
        this.options = options;
    }
}

public class SignMessageOptions
{
    public bool? hashMessage;     // Whether to hash the message
    public bool? arrayifyMessage; // Whether to convert the message to an array

    public SignMessageOptions(bool? hashMessage = null, bool? arrayifyMessage = null)
    {
        this.hashMessage = hashMessage;
        this.arrayifyMessage = arrayifyMessage;
    }
}
```

**Example:**

```csharp
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($"Wallet not ready. State: {state}");
            }
            
            // Create request and sign
            var request = new SignMessageRequest(message);
            var signature = await openfort.SignMessage(request);
            
            Debug.Log($"Message '{message}' signed successfully");
            Debug.Log($"Signature: {signature}");
            
            return signature;
        }
        catch (Exception e)
        {
            Debug.LogError($"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](https://docs.metamask.io/wallet/reference/eth_signtypeddata_v4/) standard.

**Method Signature:**

```csharp
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:**

```csharp
public class SignTypedDataRequest
{
    public TypedDataDomain domain;                          // Domain for the typed data
    public Dictionary<string, List<TypedDataField>> types;  // Types for the typed data
    public Dictionary<string, object> value;                // Value for the typed data

    public SignTypedDataRequest(
        TypedDataDomain domain,
        Dictionary<string, List<TypedDataField>> types,
        Dictionary<string, object> value)
    {
        this.domain = domain;
        this.types = types;
        this.value = value;
    }
}

public class TypedDataDomain
{
    public string name;
    public string version;
    public int chainId;
    public string verifyingContract;

    public TypedDataDomain(string name, string version, int chainId, string verifyingContract)
    {
        this.name = name;
        this.version = version;
        this.chainId = chainId;
        this.verifyingContract = verifyingContract;
    }
}

public class TypedDataField
{
    public string Name { get; set; }
    public string Type { get; set; }

    public TypedDataField(string name, string type)
    {
        this.Name = name;
        this.Type = type;
    }
}
```

**Example:**

```csharp
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($"Wallet not ready. State: {state}");
            }

            // Define the domain
            var domain = new TypedDataDomain("GameLeaderboard", "1", 80002, contractAddress);

            // Define the types
            var types = new Dictionary<string, List<TypedDataField>>
            {
                {
                    "ScoreEntry", new List<TypedDataField>
                    {
                        new TypedDataField { Name = "player", Type = "string" },
                        new TypedDataField { Name = "score", Type = "uint256" },
                        new TypedDataField { 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($"Score entry signed for {playerName}: {score}");
            return signature;
        }
        catch (Exception e)
        {
            Debug.LogError($"Failed to sign typed data: {e.Message}");
            throw;
        }
    }
}
```

## Complete Example

Here's a comprehensive example combining both message types:

```csharp
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 = $"Signature: {signature.Substring(0, 20)}...";
        }
        catch (Exception e)
        {
            signatureOutput.text = $"Error: {e.Message}";
        }
    }
    
    private async UniTaskVoid SignGameData()
    {
        try
        {
            await WaitForWalletReady();

            // Example game data
            var domain = new TypedDataDomain("Unity Game", "1", 80002, "0x0000000000000000000000000000000000000000");

            var types = new Dictionary<string, List<TypedDataField>>
            {
                {
                    "GameData", new List<TypedDataField>
                    {
                        new TypedDataField { Name = "level", Type = "uint256" },
                        new TypedDataField { 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 = $"Typed signature: {signature.Substring(0, 20)}...";
        }
        catch (Exception e)
        {
            signatureOutput.text = $"Error: {e.Message}";
        }
    }
    
    private async UniTask WaitForWalletReady()
    {
        while (true)
        {
            var state = await openfort.GetEmbeddedState();
            if (state == EmbeddedState.READY) return;
            await UniTask.Delay(100);
        }
    }
}
```

## Examples

<HoverCardLayout>
  <HoverCardLink description="An integration with Google Play Games using Firebase Auth as a third party auth provider to create a non-custodial embedded wallet" href="https://github.com/openfort-xyz/sample-unity-firebaseauth-embedded-signer" title="Unity Sample Android Embedded Wallet" subtitle="GitHub repository" icon={Smartphone} color="#10B981" />

  <HoverCardLink description="An integration with Openfort Auth with non-custodial embedded wallet" href="https://github.com/openfort-xyz/sample-unity-webgl-embedded-signer" title="Unity Sample WebGL Embedded Wallet" subtitle="GitHub repository" icon={Globe} color="#8B5CF6" />
</HoverCardLayout>
