Skip to content

Using Smart Wallets

To use smart wallets, you could use the EIP1193 provider or use a backend. This guide teaches how to make different requests to the smart wallet with the backend and Unity (it's easier to do so in the context of gaming because no need to encode transactions with Unity).

Methods

SendSignatureTransactionIntentRequest

Sign and send a transaction intent that was created by your backend.

Method Signature:
public async UniTask<TransactionIntentResponse> SendSignatureTransactionIntentRequest(SignatureTransactionIntentRequest request)
Parameters:
  • SignatureTransactionIntentRequest request - Transaction intent request with ID and user operation hash
Returns:
  • UniTask<TransactionIntentResponse> - Transaction response with transaction hash
SignatureTransactionIntentRequest Structure:
public class SignatureTransactionIntentRequest
{
    public string TransactionIntentId { get; set; }
    public string UserOperationHash { get; set; }
    public string Signature { get; set; }        // Optional - SDK generates if null
    public bool Optimistic { get; set; }         // Optional - default false
}
Example:
using System;
using UnityEngine;
using UnityEngine.Networking;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
 
public class SmartWalletTransactions : MonoBehaviour
{
    private OpenfortSDK openfort;
    private string backendUrl = "https://your-backend.com/api";
    private string authToken; // Your user's auth token
    
    private async void Start()
    {
        openfort = await OpenfortSDK.Init(
            "YOUR_OPENFORT_PUBLISHABLE_KEY",
            "YOUR_SHIELD_PUBLISHABLE_KEY"
        );
    }
    
    public async UniTask<TransactionIntentResponse> ExecuteTransaction(string transactionType, object parameters = null)
    {
        try
        {
            // Step 1: Create transaction intent via backend
            var backendResponse = await CreateTransactionIntent(transactionType, parameters);
            
            if (backendResponse?.NextAction == null)
            {
                Debug.Log("Transaction completed without signature required");
                return backendResponse;
            }
            
            // Step 2: Sign the transaction with embedded wallet
            return await SignAndSendTransaction(backendResponse);
        }
        catch (Exception e)
        {
            Debug.LogError(quot;Transaction failed: {e.Message}");
            throw;
        }
    }
    
    private async UniTask<TransactionIntentResponse> CreateTransactionIntent(string transactionType, object parameters)
    {
        var requestData = new
        {
            type = transactionType,
            parameters = parameters
        };
        
        string jsonData = JsonConvert.SerializeObject(requestData);
        
        using var webRequest = UnityWebRequest.Post(quot;{backendUrl}/transaction-intent", jsonData);
        webRequest.SetRequestHeader("Authorization", quot;Bearer {authToken}");
        webRequest.SetRequestHeader("Content-Type", "application/json");
        
        await webRequest.SendWebRequest();
        
        if (webRequest.result != UnityWebRequest.Result.Success)
        {
            throw new Exception(quot;Backend request failed: {webRequest.error}");
        }
        
        var responseText = webRequest.downloadHandler.text;
        return JsonConvert.DeserializeObject<TransactionIntentResponse>(responseText);
    }
    
    private async UniTask<TransactionIntentResponse> SignAndSendTransaction(TransactionIntentResponse backendResponse)
    {
        // Ensure wallet is ready
        var state = await openfort.GetEmbeddedState();
        if (state != EmbeddedState.READY)
        {
            throw new InvalidOperationException(quot;Wallet not ready. State: {state}");
        }
        
        // Create signature request
        var signatureRequest = new SignatureTransactionIntentRequest
        {
            TransactionIntentId = backendResponse.Id,
            UserOperationHash = backendResponse.NextAction.Payload.UserOpHash,
            Signature = null, // SDK will generate
            Optimistic = true
        };
        
        // Sign and send
        var result = await openfort.SendSignatureTransactionIntentRequest(signatureRequest);
        
        Debug.Log(quot;Transaction executed successfully: {result.Id}");
        if (result.Response?.TransactionHash != null)
        {
            Debug.Log(quot;Transaction hash: {result.Response.TransactionHash}");
        }
        
        return result;
    }
}
 
// Response models
[Serializable]
public class TransactionIntentResponse
{
    public string Id { get; set; }
    public NextAction NextAction { get; set; }
    public TransactionResponse Response { get; set; }
}
 
[Serializable]
public class NextAction
{
    public string Type { get; set; }
    public NextActionPayload Payload { get; set; }
}
 
[Serializable]
public class NextActionPayload
{
    public string UserOpHash { get; set; }
}
 
[Serializable]
public class TransactionResponse
{
    public string TransactionHash { get; set; }
}

Transaction Types

Complete Example

Here's a comprehensive example that handles different transaction types:

using System;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
 
public class SmartWalletDemo : MonoBehaviour
{
    [Header("UI References")]
    [SerializeField] private Button mintButton;
    [SerializeField] private Button transferButton;
    [SerializeField] private Button batchButton;
    [SerializeField] private TMPro.TextMeshProUGUI statusText;
    
    private SmartWalletTransactions transactionManager;
    
    private async void Start()
    {
        transactionManager = GetComponent<SmartWalletTransactions>();
        
        mintButton.onClick.AddListener(() => MintNFT().Forget());
        transferButton.onClick.AddListener(() => TransferTokens().Forget());
        batchButton.onClick.AddListener(() => BatchTransaction().Forget());
    }
    
    private async UniTaskVoid MintNFT()
    {
        statusText.text = "Minting NFT...";
        
        try
        {
            var mintParams = new {
                contractId = "con_nft_contract",
                functionName = "mint",
                functionArgs = new[] { "player_address" }
            };
            
            var result = await transactionManager.ExecuteTransaction("simple", mintParams);
            statusText.text = quot;NFT minted! TX: {result.Response?.TransactionHash}";
        }
        catch (Exception e)
        {
            statusText.text = quot;Mint failed: {e.Message}";
        }
    }
    
    private async UniTaskVoid TransferTokens()
    {
        statusText.text = "Transferring tokens...";
        
        try
        {
            var transferParams = new {
                recipient = "0x742d35Cc6Dd62c4532aD096a421c2c80b0B8aAdA",
                amount = "50000000000000000" // 0.05 MATIC
            };
            
            var result = await transactionManager.ExecuteTransaction("native", transferParams);
            statusText.text = quot;Transfer complete! TX: {result.Response?.TransactionHash}";
        }
        catch (Exception e)
        {
            statusText.text = quot;Transfer failed: {e.Message}";
        }
    }
    
    private async UniTaskVoid BatchTransaction()
    {
        statusText.text = "Executing batch transaction...";
        
        try
        {
            var batchParams = new {
                operations = new[] {
                    new { contract = "con_token", function = "approve", args = new[] { "spender", "1000" } },
                    new { contract = "con_dex", function = "swap", args = new[] { "1000" } }
                }
            };
            
            var result = await transactionManager.ExecuteTransaction("batch", batchParams);
            statusText.text = quot;Batch complete! TX: {result.Response?.TransactionHash}";
        }
        catch (Exception e)
        {
            statusText.text = quot;Batch failed: {e.Message}";
        }
    }
}

Examples

Unity Sample Android

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

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