Skip to content

Commit

Permalink
Switching between eoa and smart account
Browse files Browse the repository at this point in the history
  • Loading branch information
skibitsky committed Jan 17, 2025
1 parent a2abd47 commit 8532e81
Show file tree
Hide file tree
Showing 19 changed files with 255 additions and 64 deletions.
24 changes: 19 additions & 5 deletions src/Reown.AppKit.Unity/Runtime/Connectors/Connector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,26 @@ protected virtual void OnChainChanged(ChainChangedEventArgs e)

public class AccountConnectedEventArgs : EventArgs
{
public Func<Task<Account>> GetAccount { get; }
public Func<Task<Account[]>> GetAccounts { get; }
[Obsolete("Use GetAccountAsync instead")]
public Func<Task<Account>> GetAccount
{
get => GetAccountAsync;
}

[Obsolete("Use GetAccountsAsync instead")]
public Func<Task<Account[]>> GetAccounts
{
get => GetAccountsAsync;
}

public Func<Task<Account>> GetAccountAsync { get; }

public Func<Task<Account[]>> GetAccountsAsync { get; }

public AccountConnectedEventArgs(Func<Task<Account>> getAccount, Func<Task<Account[]>> getAccounts)
{
GetAccount = getAccount;
GetAccounts = getAccounts;
GetAccountAsync = getAccount;
GetAccountsAsync = getAccounts;
}
}

Expand Down Expand Up @@ -267,6 +280,7 @@ public enum ConnectorType
{
None,
WalletConnect,
WebGl
WebGl,
Profile
}
}
3 changes: 3 additions & 0 deletions src/Reown.AppKit.Unity/Runtime/Connectors/Profile.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

107 changes: 107 additions & 0 deletions src/Reown.AppKit.Unity/Runtime/Connectors/Profile/ProfileConnector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Reown.Sign.Models;
using UnityEngine;

namespace Reown.AppKit.Unity.Profile
{
public class ProfileConnector : WalletConnectConnector
{
public string Email { get; private set; }

public Account[] SmartAccounts { get; private set; }

public Account[] EoaAccounts { get; private set; }

public AccountType PreferredAccountType { get; private set; }

public Account PreferredAccount { get; private set; }

private const string PreferredAccountTypeKey = "PreferredAccount";

public ProfileConnector()
{
Type = ConnectorType.Profile;
}

protected override async void OnAccountConnected(AccountConnectedEventArgs e)
{
try
{
var addressProvider = SignClient.AddressProvider;
var sessionProperties = addressProvider.DefaultSession.SessionProperties;

SmartAccounts = JsonConvert
.DeserializeObject<string[]>(sessionProperties["smartAccounts"])
.Select(x => new Account(x))
.ToArray();

var allAccounts = await GetAccountsAsyncCore();
EoaAccounts = allAccounts
.Except(SmartAccounts)
.ToArray();

Email = sessionProperties["email"];

base.OnAccountConnected(e);

var preferredAccountTypeStr = PlayerPrefs.GetString(PreferredAccountTypeKey);
var preferredAccountType = Enum.TryParse<AccountType>(preferredAccountTypeStr, out var accountType)
? accountType
: AccountType.SmartAccount;
SetPreferredAccount(preferredAccountType);
}
catch (Exception exception)
{
Debug.LogException(exception);
}
}

public void SetPreferredAccount(AccountType accountType)
{
Debug.Log($"SetPreferredAccount: {accountType}. Current: {PreferredAccountType}");
if (PreferredAccountType == accountType)
return;

SetPreferredAccountCore(accountType);
OnAccountChanged(new AccountChangedEventArgs(GetCurrentAccount()));
}

private void SetPreferredAccountCore(AccountType accountType)
{
if (PreferredAccountType == accountType)
return;

if (AppKit.NetworkController.ActiveChain == null)
return;

var chainId = AppKit.NetworkController.ActiveChain.ChainId;

// Find preferred account for the current chain
PreferredAccount = accountType == AccountType.SmartAccount
? SmartAccounts.First(a => a.ChainId == chainId)
: EoaAccounts.First(a => a.ChainId == chainId);

PreferredAccountType = accountType;

// The preferred account type is saved so it can be recovered after the session is resumed
PlayerPrefs.SetString(PreferredAccountTypeKey, accountType.ToString());
}

protected override Account GetCurrentAccount()
{
return PreferredAccount != default
? PreferredAccount
: base.GetCurrentAccount();
}
}

public enum AccountType
{
None,
SmartAccount,
Eoa
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ protected override Task InitializeAsyncCore(AppKitConfig config, SignClientUnity

private void ActiveSessionChangedHandler(object sender, Session session)
{
if (session == null)
if (session == null || IsAccountConnected)
return;

var currentAccount = GetCurrentAccount();
Expand All @@ -53,6 +53,9 @@ private void ActiveSessionChangedHandler(object sender, Session session)

private async void ActiveChainIdChangedHandler(object sender, SessionEvent<JToken> sessionEvent)
{
if (!IsAccountConnected)
return;

if (sessionEvent.ChainId == "eip155:0")
return;

Expand Down Expand Up @@ -213,14 +216,13 @@ protected override Task<Account> GetAccountAsyncCore()

protected override Task<Account[]> GetAccountsAsyncCore()
{
var caipAddresses = _signClient.AddressProvider.AllAccounts();
return Task.FromResult(caipAddresses.Select(caip25Address => new Account(caip25Address.Address, caip25Address.ChainId)).ToArray());
var accounts = _signClient.AddressProvider.AllAccounts();
return Task.FromResult(accounts.ToArray());
}

private Account GetCurrentAccount()
protected virtual Account GetCurrentAccount()
{
var caipAddress = _signClient.AddressProvider.CurrentAccount();
return new Account(caipAddress.Address, caipAddress.ChainId);
return _signClient.AddressProvider.CurrentAccount();
}

private bool ActiveSessionSupportsMethod(string method)
Expand Down
19 changes: 17 additions & 2 deletions src/Reown.AppKit.Unity/Runtime/Controllers/ConnectorController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Reown.AppKit.Unity.Profile;
using Reown.Sign.Models;
using Reown.Sign.Unity;
using UnityEngine;
Expand Down Expand Up @@ -52,7 +53,7 @@ protected override async Task InitializeAsyncCore(AppKitConfig config, SignClien
webGlConnector.AccountChanged += AccountChangedHandler;
webGlConnector.ChainChanged += ChainChangedHandler;

_connectors.Add(ConnectorType.WebGl, webGlConnector);
RegisterConnector(ConnectorType.WebGl, webGlConnector);

// Only one connector is supported on WebGL
ActiveConnector = webGlConnector;
Expand All @@ -64,7 +65,16 @@ protected override async Task InitializeAsyncCore(AppKitConfig config, SignClien
walletConnectConnector.AccountChanged += AccountChangedHandler;
walletConnectConnector.ChainChanged += ChainChangedHandler;
walletConnectConnector.SignatureRequested += SignatureRequestedHandler;
_connectors.Add(ConnectorType.WalletConnect, walletConnectConnector);
RegisterConnector(ConnectorType.WalletConnect, walletConnectConnector);

// --- Reown Profile Connector
var profileConnector = new ProfileConnector();
profileConnector.AccountConnected += (_, e) => ConnectorAccountConnected(profileConnector, e);
profileConnector.AccountDisconnected += ConnectorAccountDisconnectedHandler;
profileConnector.AccountChanged += AccountChangedHandler;
profileConnector.ChainChanged += ChainChangedHandler;
profileConnector.SignatureRequested += SignatureRequestedHandler;
RegisterConnector(ConnectorType.Profile, profileConnector);
#endif

await Task.WhenAll(_connectors.Values.Select(c => c.InitializeAsync(config, signClient)));
Expand Down Expand Up @@ -117,6 +127,11 @@ protected override Task<Account[]> GetAccountsAsyncCore()
return ActiveConnector.GetAccountsAsync();
}

public void RegisterConnector(ConnectorType connectorType, Connector connector)
{
_connectors.Add(connectorType, connector);
}

public bool TryGetConnector<T>(ConnectorType connectorType, out T connector) where T : Connector
{
var ok = _connectors.TryGetValue(connectorType, out var uncasedConnector);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ protected override void ConnectorChainChangedHandlerCore(object sender, Connecto

protected override async void ConnectorAccountConnectedHandlerCore(object sender, Connector.AccountConnectedEventArgs e)
{
var accounts = await e.GetAccounts();
var accounts = await e.GetAccountsAsync();
var previousChain = ActiveChain;

if (ActiveChain == null)
{
var defaultAccount = await e.GetAccount();
var defaultAccount = await e.GetAccountAsync();

if (Chains.TryGetValue(defaultAccount.ChainId, out var defaultAccountChain))
{
Expand All @@ -87,7 +87,7 @@ protected override async void ConnectorAccountConnectedHandlerCore(object sender
}
else
{
var defaultAccount = await e.GetAccount();
var defaultAccount = await e.GetAccountAsync();
if (defaultAccount.ChainId == ActiveChain.ChainId)
return;

Expand Down
19 changes: 13 additions & 6 deletions src/Reown.AppKit.Unity/Runtime/Evm/EvmService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Numerics;
using System.Threading.Tasks;
using Reown.Sign.Unity;
using UnityEngine;

namespace Reown.AppKit.Unity
{
Expand All @@ -25,20 +26,26 @@ public Task<BigInteger> GetBalanceAsync(string address)

// -- Sign Message ---------------------------------------------

public Task<string> SignMessageAsync(string message)
public async Task<string> SignMessageAsync(string message, string address = null)
{
if (string.IsNullOrWhiteSpace(message))
throw new ArgumentNullException(nameof(message));

return SignMessageAsyncCore(message);
address ??= (await AppKit.GetAccountAsync()).Address;

Debug.Log($"SignMessageAsync: {message}, {address}");

return await SignMessageAsyncCore(message, address);
}

public Task<string> SignMessageAsync(byte[] rawMessage)
public async Task<string> SignMessageAsync(byte[] rawMessage, string address = null)
{
if (rawMessage == null || rawMessage.Length == 0)
throw new ArgumentNullException(nameof(rawMessage));

return SignMessageAsyncCore(rawMessage);
address ??= (await AppKit.GetAccountAsync()).Address;

return await SignMessageAsyncCore(rawMessage, address);
}


Expand Down Expand Up @@ -164,8 +171,8 @@ public Task<BigInteger> GetGasPriceAsync()

protected abstract Task InitializeAsyncCore(SignClientUnity signClient);
protected abstract Task<BigInteger> GetBalanceAsyncCore(string address);
protected abstract Task<string> SignMessageAsyncCore(string message);
protected abstract Task<string> SignMessageAsyncCore(byte[] rawMessage);
protected abstract Task<string> SignMessageAsyncCore(string message, string address);
protected abstract Task<string> SignMessageAsyncCore(byte[] rawMessage, string address);
protected abstract Task<bool> VerifyMessageSignatureAsyncCore(string address, string message, string signature);
protected abstract Task<string> SignTypedDataAsyncCore(string dataJson);
protected abstract Task<bool> VerifyTypedDataSignatureAsyncCore(string address, string dataJson, string signature);
Expand Down
8 changes: 4 additions & 4 deletions src/Reown.AppKit.Unity/Runtime/Evm/NethereumEvmService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,16 @@ protected override async Task<BigInteger> GetBalanceAsyncCore(string address)

// -- Sign Message ---------------------------------------------

protected override async Task<string> SignMessageAsyncCore(string message)
protected override async Task<string> SignMessageAsyncCore(string message, string address)
{
var encodedMessage = message.ToHexUTF8();
return await Web3.Client.SendRequestAsync<string>("personal_sign", null, encodedMessage);
return await Web3.Client.SendRequestAsync<string>("personal_sign", null, encodedMessage, address);
}

protected override Task<string> SignMessageAsyncCore(byte[] rawMessage)
protected override Task<string> SignMessageAsyncCore(byte[] rawMessage, string address)
{
var encodedMessage = rawMessage.ToHex(true);
return Web3.Client.SendRequestAsync<string>("personal_sign", null, encodedMessage);
return Web3.Client.SendRequestAsync<string>("personal_sign", null, encodedMessage, address);
}


Expand Down
8 changes: 4 additions & 4 deletions src/Reown.AppKit.Unity/Runtime/Evm/WagmiEvmService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ protected override async Task<BigInteger> GetBalanceAsyncCore(string address)
return BigInteger.Parse(result.value);
}

protected override Task<string> SignMessageAsyncCore(string message)
protected override Task<string> SignMessageAsyncCore(string message, string address)
{
return WagmiInterop.SignMessageAsync(message);
return WagmiInterop.SignMessageAsync(message, address);
}

protected override Task<string> SignMessageAsyncCore(byte[] rawMessage)
protected override Task<string> SignMessageAsyncCore(byte[] rawMessage, string address)
{
return WagmiInterop.SignMessageAsync(rawMessage);
return WagmiInterop.SignMessageAsync(rawMessage, address);
}

protected override Task<bool> VerifyMessageSignatureAsyncCore(string address, string message, string signature)
Expand Down
Loading

0 comments on commit 8532e81

Please sign in to comment.