Skip to content

Commit bd83494

Browse files
SIWE Generation (#47)
Co-authored-by: Joaquim Verges <[email protected]>
1 parent 653e4f8 commit bd83494

File tree

8 files changed

+238
-214
lines changed

8 files changed

+238
-214
lines changed

Assets/Thirdweb/Core/Scripts/ThirdwebSDK.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using Nethereum.Siwe;
23
using Nethereum.Web3;
34
using Nethereum.Web3.Accounts;
45
using UnityEngine;
@@ -85,28 +86,25 @@ public struct BiconomyOptions
8586

8687
public Storage storage;
8788

88-
[System.Serializable]
8989
public class NativeSession
9090
{
9191
public int lastChainId = -1;
9292
public string lastRPC = null;
9393
public Account account = null;
9494
public Web3 web3 = null;
95+
public Options options;
96+
public SiweMessageService siweSession;
9597
}
9698

9799
public NativeSession nativeSession;
98100

99-
public Options options;
100-
101101
/// <summary>
102102
/// Create an instance of the thirdweb SDK. Requires a webGL browser context.
103103
/// </summary>
104104
/// <param name="chainOrRPC">The chain name or RPC url to connect to</param>
105105
/// <param name="options">Configuration options</param>
106106
public ThirdwebSDK(string chainOrRPC, int chainId = -1, Options options = new Options())
107107
{
108-
this.options = options;
109-
110108
this.chainOrRPC = chainOrRPC;
111109
this.wallet = new Wallet();
112110
this.deployer = new Deployer();
@@ -123,6 +121,8 @@ public class NativeSession
123121
nativeSession.lastRPC = rpc;
124122
nativeSession.lastChainId = chainId;
125123
nativeSession.web3 = new Web3(nativeSession.lastRPC);
124+
nativeSession.options = options;
125+
nativeSession.siweSession = new Nethereum.Siwe.SiweMessageService();
126126
}
127127
else
128128
{

Assets/Thirdweb/Core/Scripts/TransactionManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ public static async Task<TransactionReceipt> ThirdwebWriteRawResult<TWFunction>(
4949
var gas = await gasEstimator.EstimateGasAsync(contractAddress, functionMessage);
5050
functionMessage.Gas = gas.Value < 100000 ? 100000 : gas.Value;
5151

52-
if (ThirdwebManager.Instance.SDK.options.gasless != null && ThirdwebManager.Instance.SDK.options.gasless.Value.openzeppelin != null)
52+
if (ThirdwebManager.Instance.SDK.nativeSession.options.gasless != null && ThirdwebManager.Instance.SDK.nativeSession.options.gasless.Value.openzeppelin != null)
5353
{
54-
string relayerUrl = ThirdwebManager.Instance.SDK.options.gasless.Value.openzeppelin?.relayerUrl;
55-
string relayerForwarderAddress = ThirdwebManager.Instance.SDK.options.gasless.Value.openzeppelin?.relayerForwarderAddress;
54+
string relayerUrl = ThirdwebManager.Instance.SDK.nativeSession.options.gasless.Value.openzeppelin?.relayerUrl;
55+
string relayerForwarderAddress = ThirdwebManager.Instance.SDK.nativeSession.options.gasless.Value.openzeppelin?.relayerForwarderAddress;
5656

5757
functionMessage.Nonce = (
5858
await ThirdwebRead<MinimalForwarder.GetNonceFunction, MinimalForwarder.GetNonceOutputDTO>(

Assets/Thirdweb/Core/Scripts/Types.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,17 +379,41 @@ public override string ToString()
379379
}
380380

381381
[System.Serializable]
382-
public struct LoginPayloadData
382+
public class LoginPayloadData
383383
{
384+
public string type;
384385
public string domain;
385386
public string address;
387+
public string statement;
388+
public string uri;
389+
public string version;
390+
public string chain_id;
386391
public string nonce;
392+
public string issued_at;
387393
public string expiration_time;
388-
public string chain_id;
394+
public string invalid_before;
395+
public List<string> resources;
396+
397+
public LoginPayloadData()
398+
{
399+
type = "evm";
400+
}
389401

390402
public override string ToString()
391403
{
392-
return $"LoginPayloadData:" + $"\n>domain: {domain}" + $"\n>address: {address}" + $"\n>nonce: {nonce}" + $"\n>expiration_time: {expiration_time}" + $"\n>chain_id: {chain_id}";
404+
return $"LoginPayloadData:"
405+
+ $"\n>type: {type}"
406+
+ $"\n>domain: {domain}"
407+
+ $"\n>address: {address}"
408+
+ $"\n>statement: {statement}"
409+
+ $"\n>uri: {uri}"
410+
+ $"\n>version: {version}"
411+
+ $"\n>chain_id: {chain_id}"
412+
+ $"\n>nonce: {nonce}"
413+
+ $"\n>issued_at: {issued_at}"
414+
+ $"\n>expiration_time: {expiration_time}"
415+
+ $"\n>invalid_before: {invalid_before}"
416+
+ $"\n>resources: {resources}";
393417
}
394418
}
395419

Assets/Thirdweb/Core/Scripts/Wallet.cs

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
using System.Threading.Tasks;
33
using Nethereum.Signer;
44
using Nethereum.Web3;
5-
using Nethereum.Web3.Accounts;
65
using UnityEngine;
76
using System;
8-
using WalletConnectSharp.Core;
97
using WalletConnectSharp.Core.Models;
10-
using WalletConnectSharp.Core.Models.Ethereum;
118
using WalletConnectSharp.Unity;
12-
using WalletConnectSharp.NEthereum.Account;
139
using WalletConnectSharp.NEthereum;
10+
using Nethereum.Siwe.Core;
11+
using Nethereum.Siwe;
12+
using System.Collections.Generic;
1413

1514
//using WalletConnectSharp.NEthereum;
1615

@@ -45,6 +44,7 @@ public async Task<string> Connect(WalletConnection? walletConnection = null, str
4544
newNativeSession.lastChainId = ThirdwebManager.Instance.SDK.nativeSession.lastChainId;
4645
newNativeSession.account = null;
4746
newNativeSession.web3 = WalletConnect.Instance.Session.BuildWeb3(new Uri(newNativeSession.lastRPC)).AsWalletAccount(true);
47+
newNativeSession.siweSession = new SiweMessageService();
4848
ThirdwebManager.Instance.SDK.nativeSession = newNativeSession;
4949
return WalletConnect.Instance.Session.Accounts[0];
5050
}
@@ -54,6 +54,7 @@ public async Task<string> Connect(WalletConnection? walletConnection = null, str
5454
newNativeSession.lastChainId = ThirdwebManager.Instance.SDK.nativeSession.lastChainId;
5555
newNativeSession.account = Utils.UnlockOrGenerateAccount(newNativeSession.lastChainId, password, null); // TODO: Allow custom private keys/passwords
5656
newNativeSession.web3 = new Web3(newNativeSession.account, newNativeSession.lastRPC);
57+
newNativeSession.siweSession = new SiweMessageService();
5758
ThirdwebManager.Instance.SDK.nativeSession = newNativeSession;
5859
return ThirdwebManager.Instance.SDK.nativeSession.account.Address;
5960
}
@@ -80,6 +81,7 @@ public async Task Disconnect()
8081
newNativeSession.lastChainId = ThirdwebManager.Instance.SDK.nativeSession.lastChainId;
8182
newNativeSession.account = null;
8283
newNativeSession.web3 = new Web3(newNativeSession.lastRPC); // fallback
84+
newNativeSession.siweSession = new SiweMessageService();
8385
ThirdwebManager.Instance.SDK.nativeSession = newNativeSession;
8486
}
8587
}
@@ -96,7 +98,105 @@ public async Task<LoginPayload> Authenticate(string domain)
9698
}
9799
else
98100
{
99-
throw new UnityException("This functionality is not yet available on your current platform.");
101+
var siwe = ThirdwebManager.Instance.SDK.nativeSession.siweSession;
102+
var siweMsg = new SiweMessage()
103+
{
104+
Resources = new List<string>(),
105+
Uri = $"https://{domain}",
106+
Statement = "Please ensure that the domain above matches the URL of the current website.",
107+
Address = await GetAddress(),
108+
Domain = domain,
109+
ChainId = (await GetChainId()).ToString(),
110+
Version = "1",
111+
Nonce = null,
112+
IssuedAt = null,
113+
ExpirationTime = null,
114+
NotBefore = null,
115+
RequestId = null
116+
};
117+
siweMsg.SetIssuedAtNow();
118+
siweMsg.SetExpirationTime(DateTime.UtcNow.AddSeconds(60 * 5));
119+
siweMsg.SetNotBefore(DateTime.UtcNow);
120+
siweMsg = siwe.AssignNewNonce(siweMsg);
121+
122+
var finalMsg = SiweMessageStringBuilder.BuildMessage(siweMsg);
123+
var signature = await Sign(finalMsg);
124+
return new LoginPayload()
125+
{
126+
signature = signature,
127+
payload = new LoginPayloadData()
128+
{
129+
domain = siweMsg.Domain,
130+
address = siweMsg.Address,
131+
statement = siweMsg.Statement,
132+
uri = siweMsg.Uri,
133+
version = siweMsg.Version,
134+
chain_id = siweMsg.ChainId,
135+
nonce = siweMsg.Nonce,
136+
issued_at = siweMsg.IssuedAt,
137+
expiration_time = siweMsg.ExpirationTime,
138+
invalid_before = siweMsg.NotBefore,
139+
resources = siweMsg.Resources,
140+
}
141+
};
142+
}
143+
}
144+
145+
public async Task<string> Verify(LoginPayload payload)
146+
{
147+
if (Utils.IsWebGLBuild())
148+
{
149+
throw new UnityException("This functionality is not available on your current platform.");
150+
}
151+
else
152+
{
153+
var siwe = ThirdwebManager.Instance.SDK.nativeSession.siweSession;
154+
var siweMessage = new SiweMessage()
155+
{
156+
Domain = payload.payload.domain,
157+
Address = payload.payload.address,
158+
Statement = payload.payload.statement,
159+
Uri = payload.payload.uri,
160+
Version = payload.payload.version,
161+
ChainId = payload.payload.chain_id,
162+
Nonce = payload.payload.nonce,
163+
IssuedAt = payload.payload.issued_at,
164+
ExpirationTime = payload.payload.expiration_time,
165+
NotBefore = payload.payload.invalid_before,
166+
Resources = payload.payload.resources,
167+
RequestId = null
168+
};
169+
var signature = payload.signature;
170+
var validUser = await siwe.IsUserAddressRegistered(siweMessage);
171+
if (validUser)
172+
{
173+
if (await siwe.IsMessageSignatureValid(siweMessage, signature))
174+
{
175+
if (siwe.IsMessageTheSameAsSessionStored(siweMessage))
176+
{
177+
if (siwe.HasMessageDateStartedAndNotExpired(siweMessage))
178+
{
179+
return siweMessage.Address;
180+
}
181+
else
182+
{
183+
return "Expired";
184+
}
185+
}
186+
else
187+
{
188+
return "Invalid Session";
189+
}
190+
}
191+
else
192+
{
193+
return "Invalid Signature";
194+
}
195+
}
196+
else
197+
{
198+
return "Invalid User";
199+
}
100200
}
101201
}
102202

@@ -138,7 +238,7 @@ public async Task<string> GetAddress()
138238
{
139239
if (Utils.ActiveWalletConnectSession())
140240
{
141-
return WalletConnect.Instance.Session.Accounts[0];
241+
return Nethereum.Util.AddressUtil.Current.ConvertToChecksumAddress(WalletConnect.Instance.Session.Accounts[0]);
142242
}
143243
else if (ThirdwebManager.Instance.SDK.nativeSession.account != null)
144244
{

Assets/Thirdweb/Examples/Scenes/Scene_Prefabs.unity

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -123,50 +123,6 @@ NavMeshSettings:
123123
debug:
124124
m_Flags: 0
125125
m_NavMeshData: {fileID: 0}
126-
--- !u!1 &89313707
127-
GameObject:
128-
m_ObjectHideFlags: 0
129-
m_CorrespondingSourceObject: {fileID: 0}
130-
m_PrefabInstance: {fileID: 0}
131-
m_PrefabAsset: {fileID: 0}
132-
serializedVersion: 6
133-
m_Component:
134-
- component: {fileID: 89313709}
135-
- component: {fileID: 89313708}
136-
m_Layer: 0
137-
m_Name: AsyncCoroutineRunner
138-
m_TagString: Untagged
139-
m_Icon: {fileID: 0}
140-
m_NavMeshLayer: 0
141-
m_StaticEditorFlags: 0
142-
m_IsActive: 1
143-
--- !u!114 &89313708
144-
MonoBehaviour:
145-
m_ObjectHideFlags: 0
146-
m_CorrespondingSourceObject: {fileID: 0}
147-
m_PrefabInstance: {fileID: 0}
148-
m_PrefabAsset: {fileID: 0}
149-
m_GameObject: {fileID: 89313707}
150-
m_Enabled: 1
151-
m_EditorHideFlags: 0
152-
m_Script: {fileID: 11500000, guid: f11ec4617f62c224b99e34972dc917a8, type: 3}
153-
m_Name:
154-
m_EditorClassIdentifier:
155-
--- !u!4 &89313709
156-
Transform:
157-
m_ObjectHideFlags: 0
158-
m_CorrespondingSourceObject: {fileID: 0}
159-
m_PrefabInstance: {fileID: 0}
160-
m_PrefabAsset: {fileID: 0}
161-
m_GameObject: {fileID: 89313707}
162-
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
163-
m_LocalPosition: {x: 0, y: 0, z: 0}
164-
m_LocalScale: {x: 1, y: 1, z: 1}
165-
m_ConstrainProportionsScale: 0
166-
m_Children: []
167-
m_Father: {fileID: 0}
168-
m_RootOrder: 6
169-
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
170126
--- !u!1 &136589466
171127
GameObject:
172128
m_ObjectHideFlags: 0
@@ -654,10 +610,6 @@ PrefabInstance:
654610
propertyPath: m_AnchorMax.y
655611
value: 0
656612
objectReference: {fileID: 0}
657-
- target: {fileID: 7216536800389251089, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
658-
propertyPath: m_AnchorMin.y
659-
value: 0
660-
objectReference: {fileID: 0}
661613
- target: {fileID: 7568917606152558407, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
662614
propertyPath: m_AnchorMax.y
663615
value: 0
@@ -988,7 +940,7 @@ PrefabInstance:
988940
objectReference: {fileID: 0}
989941
- target: {fileID: 7702873693426126306, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
990942
propertyPath: m_AnchoredPosition.x
991-
value: -50
943+
value: -49.999878
992944
objectReference: {fileID: 0}
993945
- target: {fileID: 7702873693426126306, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
994946
propertyPath: m_AnchoredPosition.y
@@ -1014,18 +966,6 @@ PrefabInstance:
1014966
propertyPath: m_SizeDelta.y
1015967
value: 0
1016968
objectReference: {fileID: 0}
1017-
- target: {fileID: 7702873693758646612, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
1018-
propertyPath: m_AnchorMax.x
1019-
value: 0
1020-
objectReference: {fileID: 0}
1021-
- target: {fileID: 7702873693758646612, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
1022-
propertyPath: m_AnchorMax.y
1023-
value: 0
1024-
objectReference: {fileID: 0}
1025-
- target: {fileID: 7702873693758646612, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
1026-
propertyPath: m_SizeDelta.x
1027-
value: 0
1028-
objectReference: {fileID: 0}
1029969
m_RemovedComponents: []
1030970
m_SourcePrefab: {fileID: 100100000, guid: 487e6840fccf4594ca24581d2b3e9d25, type: 3}
1031971
--- !u!224 &866517574 stripped

Assets/Thirdweb/Examples/Scripts/Prefabs/Prefab_ConnectWalletNative.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public async void OnConnect(WalletNative _wallet, string password = null)
143143
address = await ThirdwebManager.Instance.SDK.wallet.Connect(null, password, null);
144144
break;
145145
case WalletNative.DeviceWalletNoPassword:
146-
address = await ThirdwebManager.Instance.SDK.wallet.Connect(null, password, null);
146+
address = await ThirdwebManager.Instance.SDK.wallet.Connect();
147147
break;
148148
case WalletNative.WalletConnect:
149149
wcSessionData = await WalletConnect.Instance.EnableWalletConnect();

Assets/Thirdweb/Examples/Scripts/Prefabs/Prefab_Miscellaneous.cs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,33 @@ public async void Authenticate()
4444
{
4545
try
4646
{
47-
LoginPayload data = await ThirdwebManager.Instance.SDK.wallet.Authenticate("example.com");
48-
Debugger.Instance.Log("[Authenticate] Successful", data.ToString());
47+
if (Utils.IsWebGLBuild())
48+
{
49+
LoginPayload data = await ThirdwebManager.Instance.SDK.wallet.Authenticate("example.com");
50+
Debugger.Instance.Log("[Authenticate] Successful", data.ToString());
51+
}
52+
else
53+
{
54+
// Generate and sign
55+
LoginPayload data = await ThirdwebManager.Instance.SDK.wallet.Authenticate("example.com");
56+
// Verify
57+
if (!Utils.IsWebGLBuild())
58+
{
59+
string resultAddressOrError = await ThirdwebManager.Instance.SDK.wallet.Verify(data);
60+
if (await ThirdwebManager.Instance.SDK.wallet.GetAddress() == resultAddressOrError)
61+
{
62+
Debugger.Instance.Log("[Authenticate] Successful", resultAddressOrError);
63+
}
64+
else
65+
{
66+
Debugger.Instance.Log("[Authenticate] Invalid", resultAddressOrError);
67+
}
68+
}
69+
else
70+
{
71+
Debugger.Instance.Log("[Authenticate] Successful", data.payload.ToString());
72+
}
73+
}
4974
}
5075
catch (System.Exception e)
5176
{

0 commit comments

Comments
 (0)