Docs

Submit Your Wallet

The Thirdweb Unity SDK comes with many built-in wallets, but you can add your own wallet to the SDK by following these steps.

Step 1 - WalletProvider

Add your wallet identifier to the WalletProvider enum in the Wallet.cs file. This enum represents the different wallet providers.

public enum WalletProvider
{
    ...,
    MyEpicWallet
}

Step 2 - Implement IThirdwebWallet

Implement the IThirdwebWallet interface for your wallet. This interface defines the methods and properties required for wallet integration.

using System.Numerics;
using System.Threading.Tasks;
using Nethereum.Web3;
using Nethereum.Web3.Accounts;

namespace Thirdweb.Wallets
{
    /// <summary>
    /// Interface for interacting with a Thirdweb wallet.
    /// </summary>
    public interface IThirdwebWallet
    {
        /// <summary>
        /// Main Connect call - should fully connect to the wallet and return the address.
        /// </summary>
        /// <param name="walletConnection">The wallet connection details.</param>
        /// <param name="rpc">The RPC endpoint.</param>
        /// <returns>The address of the connected wallet.</returns>
        Task<string> Connect(WalletConnection walletConnection, string rpc);

        /// <summary>
        /// Main Disconnect call - should fully disconnect from the wallet and reset any variables.
        /// </summary>
        Task Disconnect();

        /// <summary>
        /// Get the local account if any, return null otherwise.
        /// </summary>
        /// <returns>The local account, or null if not available.</returns>
        Account GetLocalAccount();

        /// <summary>
        /// Return the address of the main account.
        /// </summary>
        /// <returns>The address of the main account.</returns>
        Task<string> GetAddress();

        /// <summary>
        /// Return the address of the signer account (if any, otherwise return GetAddress).
        /// </summary>
        /// <returns>The address of the signer account.</returns>
        Task<string> GetSignerAddress();

        /// <summary>
        /// Return the WalletProvider you added above.
        /// </summary>
        /// <returns>The WalletProvider.</returns>
        WalletProvider GetProvider();

        /// <summary>
        /// Return the WalletProvider of the signer account (if any, otherwise return GetProvider).
        /// </summary>
        /// <returns>The WalletProvider of the signer account.</returns>
        WalletProvider GetSignerProvider();

        /// <summary>
        /// Return the Web3 Nethereum provider for the main account - must override Task<RpcResponseMessage> SendAsync.
        /// </summary>
        /// <returns>The Web3 Nethereum provider for the main account.</returns>
        Task<Web3> GetWeb3();

        /// <summary>
        /// Return the Web3 Nethereum provider for the signer account (if any, otherwise return GetWeb3).
        /// </summary>
        /// <returns>The Web3 Nethereum provider for the signer account.</returns>
        Task<Web3> GetSignerWeb3();

        /// <summary>
        /// Return whether the wallet is currently connected (e.g. Web3 != null).
        /// </summary>
        /// <returns>True if the wallet is connected; otherwise, false.</returns>
        Task<bool> IsConnected();

        /// <summary>
        /// Prepares the wallet for a network switch and returns an actionable response.
        /// </summary>
        /// <param name="newChainId">The new chain ID to switch to.</param>
        /// <param name="newRpc">The new RPC endpoint to switch to.</param>
        /// <returns>A <see cref="NetworkSwitchAction"/> indicating the action to be taken.</returns>
        Task<NetworkSwitchAction> PrepareForNetworkSwitch(BigInteger newChainId, string newRpc);
    }

    public enum NetworkSwitchAction
    {
        /// <summary>
        /// Indicates that the network switch can proceed. The SDK should continue with the wallet_switchEthereumChain RPC call.
        /// </summary>
        ContinueSwitch,

        /// <summary>
        /// Indicates that the wallet has already handled the network switch internally. There's no need to make the wallet_switchEthereumChain RPC call.
        /// </summary>
        Handled,

        /// <summary>
        /// Indicates that the network switching feature is completely unsupported for the current wallet implementation.
        /// </summary>
        Unsupported
    }
}

Step 3 - Instantiate Your Wallet in ThirdwebSession.Connect

In the ThirdwebSession.cs file, instantiate your wallet in the Connect method.

switch (walletConnection.provider)
{
    // ...
    case WalletProvider.MyWalletProvider:
        ActiveWallet = new MyWallet();
        break;
    // ...
}

Advanced

WalletConnection

If your wallet implementation requires additional data for the constructor or connect methods, you can add fields to the WalletConnection class in the Wallet.cs file.

public class WalletConnection
{
    // ...
    public string additionalData;

    public WalletConnection(/* ... */, string additionalData = null)
    {
        // ...
        this.additionalData = additionalData;
    }
}

Nethereum Web3 Provider

All RPC calls will pass through Nethereum's Web3 provider.

You'll need four classes to fully implement the provider, here's a Smart Wallet example:

Extending IAccount

using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Accounts;
using Nethereum.RPC.AccountSigning;
using Nethereum.RPC.NonceServices;
using Nethereum.RPC.TransactionManagers;

namespace Thirdweb.AccountAbstraction
{
    public class SmartWalletAccount : IAccount
    {
        private readonly SmartWallet _wallet;
        private readonly IClient _client;

        public string Address
        {
            get { return _wallet.Accounts[0]; }
        }

        public ITransactionManager TransactionManager { get; }
        public INonceService NonceService { get; set; }
        public IAccountSigningService AccountSigningService { get; }

        public IClient Client
        {
            get { return _client; }
        }

        public SmartWalletAccount(SmartWallet wallet, IClient client)
        {
            _wallet = wallet;
            _client = client;
            TransactionManager = new SmartWalletTransactionManager(this);
            NonceService = new InMemoryNonceService(Address, client);
            AccountSigningService = new AccountSigningService(client);
        }
    }
}

Extending ClientBase

using System;
using System.Linq;
using System.Threading.Tasks;
using Nethereum.JsonRpc.Client;
using Nethereum.JsonRpc.Client.RpcMessages;

namespace Thirdweb.AccountAbstraction
{
    public class SmartWalletClient : ClientBase
    {
        private SmartWallet _smartWallet;

        public SmartWalletClient(SmartWallet smartWallet)
        {
            this._smartWallet = smartWallet;
        }

        private static readonly Random rng = new Random();
        private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        public static long GenerateRpcId()
        {
            var date = (long)((DateTime.UtcNow - UnixEpoch).TotalMilliseconds) * (10L * 10L * 10L);
            var extra = (long)Math.Floor(rng.NextDouble() * (10.0 * 10.0 * 10.0));
            return date + extra;
        }

        protected override async Task<RpcResponseMessage> SendAsync(RpcRequestMessage message, string route = null)
        {
            message.Id = GenerateRpcId();
            return await _smartWallet.Request(message);
        }

        protected override Task<RpcResponseMessage[]> SendAsync(RpcRequestMessage[] requests)
        {
            return Task.WhenAll(requests.Select(r => SendAsync(r)));
        }
    }
}

Extending TransactionManagerBase (not used in practice)

namespace Thirdweb.AccountAbstraction
{
    public class SmartWalletTransactionManager : Nethereum.RPC.TransactionManagers.TransactionManager
    {
        public SmartWalletTransactionManager(SmartWalletAccount account)
            : base(account.Client)
        {
            Account = account;
        }
    }
}

Finally, an extension to create a Web3 provider

using Nethereum.Web3;

namespace Thirdweb.AccountAbstraction
{
    public static class SmartWalletNEthereumExtensions
    {
        public static Web3 CreateWeb3(this SmartWallet smartWallet)
        {
            var client = new SmartWalletClient(smartWallet);
            var account = new SmartWalletAccount(smartWallet, client);
            return new Web3(account, client);
        }
    }
}

Submitting Your Wallet

If you think your wallet implementation would be useful to others, please consider sharing it by opening a PR to the thirdweb-dev/unity-sdk repository.

Unity SDK

Unity SDK is open-source. You can view the source code and contribute to it on GitHub