Skip to content

Commit 5e6965a

Browse files
authored
Support BigInteger ids and network switching at runtime (#96)
1 parent 6ed0bdf commit 5e6965a

10 files changed

+202
-41
lines changed

Assets/Thirdweb/Core/Scripts/ThirdwebSession.cs

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public ThirdwebSession(ThirdwebSDK.Options options, BigInteger chainId, string r
4545

4646
#endregion
4747

48-
#region Public Methods
48+
#region Internal Methods
4949

50-
public async Task<string> Connect(WalletConnection walletConnection)
50+
internal async Task<string> Connect(WalletConnection walletConnection)
5151
{
5252
switch (walletConnection.provider)
5353
{
@@ -91,7 +91,14 @@ public async Task<string> Connect(WalletConnection walletConnection)
9191
Web3 = await ActiveWallet.GetWeb3();
9292
Web3.Client.OverridingRequestInterceptor = new ThirdwebInterceptor(ActiveWallet);
9393

94-
await EnsureCorrectNetwork();
94+
try
95+
{
96+
await EnsureCorrectNetwork(ChainId);
97+
}
98+
catch (System.Exception e)
99+
{
100+
Debug.LogWarning("WalletProvider unable to switch chains, proceeding anyway. Error:" + e.Message);
101+
}
95102

96103
var addy = await ActiveWallet.GetAddress();
97104

@@ -100,59 +107,84 @@ public async Task<string> Connect(WalletConnection walletConnection)
100107
return addy;
101108
}
102109

103-
public async Task Disconnect()
110+
internal async Task Disconnect()
104111
{
105112
await ActiveWallet.Disconnect();
106113
ThirdwebManager.Instance.SDK.session = new ThirdwebSession(Options, ChainId, RPC);
107114
}
108115

109-
public async Task<T> Request<T>(string method, params object[] parameters)
116+
internal async Task<T> Request<T>(string method, params object[] parameters)
110117
{
111118
var request = new RpcRequest(Nonce, method, parameters);
112119
Nonce++;
113120
return await Web3.Client.SendRequestAsync<T>(request);
114121
}
115122

116-
#endregion
123+
internal async Task EnsureCorrectNetwork(BigInteger newChainId)
124+
{
125+
ThirdwebChainData newChainData = null;
126+
try
127+
{
128+
newChainData = Options.supportedChains.ToList().Find(x => x.chainId == new HexBigInteger(newChainId).HexValue);
129+
}
130+
catch
131+
{
132+
throw new UnityException("The chain you are trying to switch to is not part of the ThirdwebManager's supported chains.");
133+
}
117134

118-
#region Private Methods
135+
NetworkSwitchAction switchResult = await ActiveWallet.PrepareForNetworkSwitch(newChainId, newChainData.rpcUrls[0]);
119136

120-
private async Task EnsureCorrectNetwork()
121-
{
122-
var hexChainId = await Request<string>("eth_chainId");
123-
var connectedChainId = (int)hexChainId.HexToBigInteger(false);
124-
if (connectedChainId != ChainId)
137+
switch (switchResult)
125138
{
126-
try
127-
{
128-
await SwitchNetwork(new ThirdwebChain() { chainId = CurrentChainData.chainId });
129-
}
130-
catch (System.Exception e)
131-
{
132-
Debug.LogWarning("Switching chain error, attempting to add chain: " + e.Message);
133-
try
139+
case NetworkSwitchAction.ContinueSwitch:
140+
var hexChainId = await Request<string>("eth_chainId");
141+
var connectedChainId = hexChainId.HexToBigInteger(false);
142+
if (connectedChainId != ChainId)
134143
{
135-
await AddNetwork(CurrentChainData);
136-
await SwitchNetwork(new ThirdwebChain() { chainId = CurrentChainData.chainId });
144+
try
145+
{
146+
await SwitchNetwork(new ThirdwebChain() { chainId = newChainData.chainId });
147+
}
148+
catch (System.Exception e)
149+
{
150+
Debug.LogWarning("Switching chain error, attempting to add chain: " + e.Message);
151+
try
152+
{
153+
await AddNetwork(newChainData);
154+
await SwitchNetwork(new ThirdwebChain() { chainId = newChainData.chainId });
155+
}
156+
catch (System.Exception f)
157+
{
158+
throw new UnityException("Adding chain error: " + f.Message);
159+
}
160+
}
137161
}
138-
catch (System.Exception f)
139-
{
140-
Debug.LogWarning("Adding chain error: " + f.Message);
141-
}
142-
}
162+
break;
163+
case NetworkSwitchAction.Handled:
164+
break;
165+
case NetworkSwitchAction.Unsupported:
166+
throw new UnityException("Network switching is not supported by the active wallet.");
143167
}
168+
169+
ChainId = newChainId;
170+
CurrentChainData = newChainData;
171+
RPC = CurrentChainData.rpcUrls[0];
172+
Web3 = await ActiveWallet.GetWeb3();
173+
Web3.Client.OverridingRequestInterceptor = new ThirdwebInterceptor(ActiveWallet);
144174
}
145175

176+
#endregion
177+
178+
#region Private Methods
179+
146180
private async Task SwitchNetwork(ThirdwebChain newChain)
147181
{
148182
await Request<object>("wallet_switchEthereumChain", new object[] { newChain });
149-
CurrentChainData.chainId = newChain.chainId;
150183
}
151184

152185
private async Task AddNetwork(ThirdwebChainData newChainData)
153186
{
154187
await Request<object>("wallet_addEthereumChain", new object[] { newChainData });
155-
CurrentChainData = newChainData;
156188
}
157189

158190
public static ThirdwebChainData FetchChainData(BigInteger chainId, string rpcOverride = null)

Assets/Thirdweb/Core/Scripts/Wallet.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ public async Task<bool> IsConnected()
302302
/// Gets the connected chainId.
303303
/// </summary>
304304
/// <returns>The connected chainId as an integer.</returns>
305-
public async Task<int> GetChainId()
305+
public async Task<BigInteger> GetChainId()
306306
{
307307
if (Utils.IsWebGLBuild())
308308
{
@@ -311,7 +311,7 @@ public async Task<int> GetChainId()
311311
else
312312
{
313313
var hexChainId = await ThirdwebManager.Instance.SDK.session.Request<string>("eth_chainId");
314-
return (int)hexChainId.HexToBigInteger(false);
314+
return hexChainId.HexToBigInteger(false);
315315
}
316316
}
317317

@@ -320,15 +320,24 @@ public async Task<int> GetChainId()
320320
/// </summary>
321321
/// <param name="chainId">The chainId to switch to.</param>
322322
/// <returns>A task representing the switching process.</returns>
323-
public async Task SwitchNetwork(int chainId)
323+
public async Task SwitchNetwork(BigInteger chainId)
324324
{
325+
if (!await IsConnected())
326+
throw new Exception("No account connected!");
327+
325328
if (Utils.IsWebGLBuild())
326329
{
327-
await Bridge.SwitchNetwork(chainId);
330+
int safeId;
331+
if (!int.TryParse(chainId.ToString(), out safeId))
332+
{
333+
throw new Exception("Chain ID too large for WebGL platforms");
334+
}
335+
336+
await Bridge.SwitchNetwork(safeId);
328337
}
329338
else
330339
{
331-
throw new UnityException("This functionality is not yet available on your current platform.");
340+
await ThirdwebManager.Instance.SDK.session.EnsureCorrectNetwork(chainId);
332341
}
333342
}
334343

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,100 @@
1+
using System.Numerics;
12
using System.Threading.Tasks;
23
using Nethereum.Web3;
34
using Nethereum.Web3.Accounts;
45

56
namespace Thirdweb.Wallets
67
{
8+
/// <summary>
9+
/// Interface for interacting with a Thirdweb wallet.
10+
/// </summary>
711
public interface IThirdwebWallet
812
{
13+
/// <summary>
14+
/// Main Connect call - should fully connect to the wallet and return the address.
15+
/// </summary>
16+
/// <param name="walletConnection">The wallet connection details.</param>
17+
/// <param name="rpc">The RPC endpoint.</param>
18+
/// <returns>The address of the connected wallet.</returns>
919
Task<string> Connect(WalletConnection walletConnection, string rpc);
20+
21+
/// <summary>
22+
/// Main Disconnect call - should fully disconnect from the wallet and reset any variables.
23+
/// </summary>
1024
Task Disconnect();
25+
26+
/// <summary>
27+
/// Get the local account if any, return null otherwise.
28+
/// </summary>
29+
/// <returns>The local account, or null if not available.</returns>
1130
Account GetLocalAccount();
31+
32+
/// <summary>
33+
/// Return the address of the main account.
34+
/// </summary>
35+
/// <returns>The address of the main account.</returns>
1236
Task<string> GetAddress();
37+
38+
/// <summary>
39+
/// Return the address of the signer account (if any, otherwise return GetAddress).
40+
/// </summary>
41+
/// <returns>The address of the signer account.</returns>
1342
Task<string> GetSignerAddress();
43+
44+
/// <summary>
45+
/// Return the WalletProvider you added above.
46+
/// </summary>
47+
/// <returns>The WalletProvider.</returns>
1448
WalletProvider GetProvider();
49+
50+
/// <summary>
51+
/// Return the WalletProvider of the signer account (if any, otherwise return GetProvider).
52+
/// </summary>
53+
/// <returns>The WalletProvider of the signer account.</returns>
1554
WalletProvider GetSignerProvider();
55+
56+
/// <summary>
57+
/// Return the Web3 Nethereum provider for the main account - must override Task<RpcResponseMessage> SendAsync.
58+
/// </summary>
59+
/// <returns>The Web3 Nethereum provider for the main account.</returns>
1660
Task<Web3> GetWeb3();
61+
62+
/// <summary>
63+
/// Return the Web3 Nethereum provider for the signer account (if any, otherwise return GetWeb3).
64+
/// </summary>
65+
/// <returns>The Web3 Nethereum provider for the signer account.</returns>
1766
Task<Web3> GetSignerWeb3();
67+
68+
/// <summary>
69+
/// Return whether the wallet is currently connected (e.g. Web3 != null).
70+
/// </summary>
71+
/// <returns>True if the wallet is connected; otherwise, false.</returns>
1872
Task<bool> IsConnected();
73+
74+
/// <summary>
75+
/// Prepares the wallet for a network switch and returns an actionable response.
76+
/// </summary>
77+
/// <param name="newChainId">The new chain ID to switch to.</param>
78+
/// <param name="newRpc">The new RPC endpoint to switch to.</param>
79+
/// <returns>A <see cref="NetworkSwitchAction"/> indicating the action to be taken.</returns>
80+
Task<NetworkSwitchAction> PrepareForNetworkSwitch(BigInteger newChainId, string newRpc);
81+
}
82+
83+
public enum NetworkSwitchAction
84+
{
85+
/// <summary>
86+
/// Indicates that the network switch can proceed. The SDK should continue with the wallet_switchEthereumChain RPC call.
87+
/// </summary>
88+
ContinueSwitch,
89+
90+
/// <summary>
91+
/// Indicates that the wallet has already handled the network switch internally. There's no need to make the wallet_switchEthereumChain RPC call.
92+
/// </summary>
93+
Handled,
94+
95+
/// <summary>
96+
/// Indicates that the network switching feature is completely unsupported for the current wallet implementation.
97+
/// </summary>
98+
Unsupported
1999
}
20100
}

Assets/Thirdweb/Core/Scripts/Wallets/ThirdwebHyperplay.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Numerics;
12
using System.Threading.Tasks;
23
using Nethereum.Web3;
34
using Nethereum.Web3.Accounts;
@@ -75,5 +76,10 @@ public Task<bool> IsConnected()
7576
{
7677
return Task.FromResult(_web3 != null);
7778
}
79+
80+
public Task<NetworkSwitchAction> PrepareForNetworkSwitch(BigInteger newChainId, string newRpc)
81+
{
82+
return Task.FromResult(NetworkSwitchAction.ContinueSwitch);
83+
}
7884
}
7985
}

Assets/Thirdweb/Core/Scripts/Wallets/ThirdwebLocalWallet.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Numerics;
12
using System.Threading.Tasks;
23
using Nethereum.Web3;
34
using Nethereum.Web3.Accounts;
@@ -75,5 +76,12 @@ public Task<bool> IsConnected()
7576
{
7677
return Task.FromResult(_web3 != null);
7778
}
79+
80+
public Task<NetworkSwitchAction> PrepareForNetworkSwitch(BigInteger newChainId, string newRpc)
81+
{
82+
_account = new Account(_account.PrivateKey, newChainId);
83+
_web3 = new Web3(_account, newRpc);
84+
return Task.FromResult(NetworkSwitchAction.Handled);
85+
}
7886
}
7987
}

Assets/Thirdweb/Core/Scripts/Wallets/ThirdwebMagicLink.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Numerics;
12
using System.Threading.Tasks;
23
using link.magic.unity.sdk;
34
using link.magic.unity.sdk.Relayer;
@@ -82,5 +83,10 @@ public Task<bool> IsConnected()
8283
{
8384
return Task.FromResult(_web3 != null);
8485
}
86+
87+
public Task<NetworkSwitchAction> PrepareForNetworkSwitch(BigInteger newChainId, string newRpc)
88+
{
89+
return Task.FromResult(NetworkSwitchAction.ContinueSwitch);
90+
}
8591
}
8692
}

Assets/Thirdweb/Core/Scripts/Wallets/ThirdwebMetamask.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Numerics;
12
using System.Threading.Tasks;
23
using MetaMask.NEthereum;
34
using MetaMask.Unity;
@@ -81,5 +82,10 @@ public Task<bool> IsConnected()
8182
{
8283
return Task.FromResult(_web3 != null);
8384
}
85+
86+
public Task<NetworkSwitchAction> PrepareForNetworkSwitch(BigInteger newChainId, string newRpc)
87+
{
88+
return Task.FromResult(NetworkSwitchAction.ContinueSwitch);
89+
}
8490
}
8591
}

0 commit comments

Comments
 (0)