Skip to content

Commit 797e1d3

Browse files
authored
Full 1271 support for all flows, remove deployOnSign option (#152)
1 parent cd26884 commit 797e1d3

File tree

11 files changed

+68135
-69062
lines changed

11 files changed

+68135
-69062
lines changed

Assets/Thirdweb/Core/Contract Definitions/Account/AccountService.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,19 @@ public Task<GetAllSignersOutputDTO> GetAllSignersQueryAsync(BlockParameter block
192192
return ContractHandler.QueryDeserializingToObjectAsync<GetAllSignersFunction, GetAllSignersOutputDTO>(null, blockParameter);
193193
}
194194

195+
public Task<byte[]> GetMessageHashQueryAsync(GetMessageHashFunction getMessageHashFunction, BlockParameter blockParameter = null)
196+
{
197+
return ContractHandler.QueryAsync<GetMessageHashFunction, byte[]>(getMessageHashFunction, blockParameter);
198+
}
199+
200+
public Task<byte[]> GetMessageHashQueryAsync(byte[] hash, BlockParameter blockParameter = null)
201+
{
202+
var getMessageHashFunction = new GetMessageHashFunction();
203+
getMessageHashFunction.Hash = hash;
204+
205+
return ContractHandler.QueryAsync<GetMessageHashFunction, byte[]>(getMessageHashFunction, blockParameter);
206+
}
207+
195208
public Task<BigInteger> GetNonceQueryAsync(GetNonceFunction getNonceFunction, BlockParameter blockParameter = null)
196209
{
197210
return ContractHandler.QueryAsync<GetNonceFunction, BigInteger>(getNonceFunction, blockParameter);
@@ -225,21 +238,19 @@ public Task<TransactionReceipt> InitializeRequestAndWaitForReceiptAsync(Initiali
225238
return ContractHandler.SendRequestAndWaitForReceiptAsync(initializeFunction, cancellationToken);
226239
}
227240

228-
public Task<string> InitializeRequestAsync(string defaultAdmin, string factory, byte[] data)
241+
public Task<string> InitializeRequestAsync(string defaultAdmin, byte[] data)
229242
{
230243
var initializeFunction = new InitializeFunction();
231244
initializeFunction.DefaultAdmin = defaultAdmin;
232-
initializeFunction.Factory = factory;
233245
initializeFunction.Data = data;
234246

235247
return ContractHandler.SendRequestAsync(initializeFunction);
236248
}
237249

238-
public Task<TransactionReceipt> InitializeRequestAndWaitForReceiptAsync(string defaultAdmin, string factory, byte[] data, CancellationTokenSource cancellationToken = null)
250+
public Task<TransactionReceipt> InitializeRequestAndWaitForReceiptAsync(string defaultAdmin, byte[] data, CancellationTokenSource cancellationToken = null)
239251
{
240252
var initializeFunction = new InitializeFunction();
241253
initializeFunction.DefaultAdmin = defaultAdmin;
242-
initializeFunction.Factory = factory;
243254
initializeFunction.Data = data;
244255

245256
return ContractHandler.SendRequestAndWaitForReceiptAsync(initializeFunction, cancellationToken);

Assets/Thirdweb/Core/Contract Definitions/Account/ContractDefinition/AccountDefinition.cs

Lines changed: 23 additions & 5 deletions
Large diffs are not rendered by default.

Assets/Thirdweb/Core/Scripts/AccountAbstraction/Core/SmartWallet.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
using Nethereum.Contracts;
1515
using Nethereum.Hex.HexConvertors.Extensions;
1616
using Thirdweb.Redcode.Awaiting;
17-
using System.Threading;
18-
using System.Collections.Concurrent;
1917
using Thirdweb.Contracts.Account.ContractDefinition;
2018

2119
namespace Thirdweb.AccountAbstraction
@@ -120,11 +118,19 @@ internal async Task ForceDeploy()
120118

121119
internal async Task<bool> VerifySignature(byte[] hash, byte[] signature)
122120
{
123-
var verifyRes = await TransactionManager.ThirdwebRead<AccountContract.IsValidSignatureFunction, AccountContract.IsValidSignatureOutputDTO>(
124-
Accounts[0],
125-
new AccountContract.IsValidSignatureFunction() { Hash = hash, Signature = signature }
126-
);
127-
return verifyRes.MagicValue.ToHex(true) == new byte[] { 0x16, 0x26, 0xba, 0x7e }.ToHex(true);
121+
try
122+
{
123+
var verifyRes = await TransactionManager.ThirdwebRead<AccountContract.IsValidSignatureFunction, AccountContract.IsValidSignatureOutputDTO>(
124+
Accounts[0],
125+
new AccountContract.IsValidSignatureFunction() { Hash = hash, Signature = signature }
126+
);
127+
return verifyRes.MagicValue.ToHex(true) == new byte[] { 0x16, 0x26, 0xba, 0x7e }.ToHex(true);
128+
}
129+
catch (Exception e)
130+
{
131+
ThirdwebDebug.LogWarning("isValidSignature call failed: " + e.Message);
132+
return false;
133+
}
128134
}
129135

130136
internal async Task<(byte[] initCode, BigInteger gas)> GetInitCode()

Assets/Thirdweb/Core/Scripts/AccountAbstraction/Core/UserOpUtils.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ public static async Task<byte[]> HashAndSignUserOp(this EntryPointContract.UserO
4242
}
4343
else
4444
{
45-
var sig = await ThirdwebManager.Instance.SDK.wallet.Sign(userOpHash.ReturnValue1.ByteArrayToHexString());
45+
var sig = await ThirdwebManager.Instance.SDK.session.Request<string>(
46+
"personal_sign",
47+
userOpHash.ReturnValue1.ByteArrayToHexString(),
48+
await ThirdwebManager.Instance.SDK.wallet.GetSignerAddress()
49+
);
4650
return sig.HexStringToByteArray();
4751
}
4852
}

Assets/Thirdweb/Core/Scripts/EIP712.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using TokenERC1155Contract = Thirdweb.Contracts.TokenERC1155.ContractDefinition;
99
using MinimalForwarder = Thirdweb.Contracts.Forwarder.ContractDefinition;
1010
using AccountContract = Thirdweb.Contracts.Account.ContractDefinition;
11-
using Nethereum.Model;
1211

1312
namespace Thirdweb
1413
{
@@ -136,6 +135,13 @@ public async static Task<string> GenerateSignature_SmartAccount(
136135
}
137136
}
138137

138+
public async static Task<string> GenerateSignature_SmartAccount_AccountMessage(string domainName, string version, BigInteger chainId, string verifyingContract, byte[] message)
139+
{
140+
var typedData = GetTypedDefinition_SmartAccount_AccountMessage(domainName, version, chainId, verifyingContract);
141+
var accountMessage = new AccountMessage { Message = message };
142+
return await ThirdwebManager.Instance.SDK.wallet.SignTypedDataV4(accountMessage, typedData);
143+
}
144+
139145
#region Typed Data Definitions
140146

141147
public static TypedData<Domain> GetTypedDefinition_TokenERC20(string domainName, string version, BigInteger chainId, string verifyingContract)
@@ -218,6 +224,31 @@ public static TypedData<Domain> GetTypedDefinition_SmartAccount(string domainNam
218224
};
219225
}
220226

227+
public static TypedData<Domain> GetTypedDefinition_SmartAccount_AccountMessage(string domainName, string version, BigInteger chainId, string verifyingContract)
228+
{
229+
return new TypedData<Domain>
230+
{
231+
Domain = new Domain
232+
{
233+
Name = domainName,
234+
Version = version,
235+
ChainId = chainId,
236+
VerifyingContract = verifyingContract,
237+
},
238+
Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountMessage)),
239+
PrimaryType = nameof(AccountMessage),
240+
};
241+
}
242+
}
243+
221244
#endregion
245+
246+
247+
public partial class AccountMessage : AccountMessageBase { }
248+
249+
public class AccountMessageBase
250+
{
251+
[Nethereum.ABI.FunctionEncoding.Attributes.Parameter("bytes", "message", 1)]
252+
public virtual byte[] Message { get; set; }
222253
}
223254
}

Assets/Thirdweb/Core/Scripts/ThirdwebManager.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,6 @@ public class ThirdwebManager : MonoBehaviour
9999
[Tooltip("Whether it should use a paymaster for gasless transactions or not")]
100100
public bool gasless;
101101

102-
[Tooltip("Indicates whether to deploy the smart wallet upon signing any type of message.")]
103-
public bool deployOnSign;
104-
105102
[Tooltip("Optional - If you want to use a custom relayer, you can provide the URL here")]
106103
public string bundlerUrl;
107104

@@ -284,7 +281,6 @@ public void Initialize(string chainIdentifier)
284281
{
285282
factoryAddress = factoryAddress,
286283
gasless = gasless,
287-
deployOnSign = deployOnSign,
288284
bundlerUrl = string.IsNullOrEmpty(bundlerUrl) ? $"https://{activeChainId}.bundler.thirdweb.com" : bundlerUrl,
289285
paymasterUrl = string.IsNullOrEmpty(paymasterUrl) ? $"https://{activeChainId}.bundler.thirdweb.com" : paymasterUrl,
290286
entryPointAddress = string.IsNullOrEmpty(entryPointAddress) ? Thirdweb.AccountAbstraction.Constants.DEFAULT_ENTRYPOINT_ADDRESS : entryPointAddress,

Assets/Thirdweb/Core/Scripts/ThirdwebSDK.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,6 @@ public struct SmartWalletConfig
112112
/// </summary>
113113
public bool gasless;
114114

115-
/// <summary>
116-
/// Indicates whether to deploy the smart wallet upon signing any type of message.
117-
/// </summary>
118-
public bool deployOnSign;
119-
120115
/// <summary>
121116
/// The URL of the bundler service.
122117
/// </summary>

Assets/Thirdweb/Core/Scripts/Utils.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,5 +637,29 @@ public static async void TrackWalletAnalytics(string clientId, string source, st
637637
ThirdwebDebug.LogWarning($"Failed to send wallet analytics: {e}");
638638
}
639639
}
640+
641+
public static byte[] HashPrefixedMessage(this byte[] messageBytes)
642+
{
643+
var signer = new EthereumMessageSigner();
644+
return signer.HashPrefixedMessage(messageBytes);
645+
}
646+
647+
public static string HashPrefixedMessage(this string message)
648+
{
649+
var signer = new EthereumMessageSigner();
650+
return signer.HashPrefixedMessage(System.Text.Encoding.UTF8.GetBytes(message)).ByteArrayToHexString();
651+
}
652+
653+
public static byte[] HashMessage(this byte[] messageBytes)
654+
{
655+
var sha3 = new Nethereum.Util.Sha3Keccack();
656+
return sha3.CalculateHash(messageBytes);
657+
}
658+
659+
public static string HashMessage(this string message)
660+
{
661+
var sha3 = new Nethereum.Util.Sha3Keccack();
662+
return sha3.CalculateHash(message);
663+
}
640664
}
641665
}

Assets/Thirdweb/Core/Scripts/Wallet.cs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using Nethereum.Signer.EIP712;
1111
using Newtonsoft.Json.Linq;
1212
using Nethereum.Hex.HexTypes;
13-
using Newtonsoft.Json;
1413
using System.Linq;
1514

1615
namespace Thirdweb
@@ -435,17 +434,56 @@ public async Task<string> Sign(string message)
435434
}
436435
else
437436
{
438-
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet && ThirdwebManager.Instance.SDK.session.Options.smartWalletConfig.Value.deployOnSign)
437+
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet)
439438
{
440439
var sw = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
441440
if (!sw.SmartWallet.IsDeployed && !sw.SmartWallet.IsDeploying)
442441
{
443442
ThirdwebDebug.Log("SmartWallet not deployed, deploying before signing...");
444443
await sw.SmartWallet.ForceDeploy();
445444
}
445+
if (sw.SmartWallet.IsDeployed)
446+
{
447+
try
448+
{
449+
byte[] originalMsgHash = System.Text.Encoding.UTF8.GetBytes(message).HashPrefixedMessage();
450+
451+
// if this fails it's a pre 712 factory
452+
await TransactionManager.ThirdwebRead<Contracts.Account.ContractDefinition.GetMessageHashFunction, Contracts.Account.ContractDefinition.GetMessageHashOutputDTO>(
453+
await GetAddress(),
454+
new Contracts.Account.ContractDefinition.GetMessageHashFunction() { Hash = originalMsgHash }
455+
);
456+
457+
string sig = await EIP712.GenerateSignature_SmartAccount_AccountMessage("Account", "1", await GetChainId(), await GetAddress(), originalMsgHash);
458+
459+
bool isValid = await RecoverAddress(message, sig) == await GetAddress();
460+
if (isValid)
461+
{
462+
return sig;
463+
}
464+
else
465+
{
466+
throw new Exception("Unable to verify signature on smart account, please make sure the smart account is deployed and the signature is valid.");
467+
}
468+
}
469+
catch (Exception e)
470+
{
471+
ThirdwebDebug.LogWarning("Error signing message with smart account typed data, falling back to personal sign: " + e.Message);
472+
}
473+
}
474+
else
475+
{
476+
throw new Exception("Smart account could not be deployed, unable to sign message.");
477+
}
446478
}
447479

448-
return await ThirdwebManager.Instance.SDK.session.Request<string>("personal_sign", message, await GetSignerAddress());
480+
var sig2 = await ThirdwebManager.Instance.SDK.session.Request<string>("personal_sign", message, await GetSignerAddress());
481+
var verify = await RecoverAddress(message, sig2) == await GetAddress();
482+
if (!verify)
483+
{
484+
throw new Exception("Unable to verify signature, please make sure the wallet is unlocked and the signature is valid.");
485+
}
486+
return sig2;
449487
}
450488
}
451489

@@ -463,7 +501,7 @@ public async Task<string> SignTypedDataV4<T, TDomain>(T data, TypedData<TDomain>
463501
if (!await IsConnected())
464502
throw new Exception("No account connected!");
465503

466-
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet && ThirdwebManager.Instance.SDK.session.Options.smartWalletConfig.Value.deployOnSign)
504+
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet)
467505
{
468506
var sw = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
469507
if (!sw.SmartWallet.IsDeployed && !sw.SmartWallet.IsDeploying)
@@ -493,6 +531,19 @@ public async Task<string> SignTypedDataV4<T, TDomain>(T data, TypedData<TDomain>
493531
uidToken.Replace(uidHex);
494532
}
495533

534+
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet)
535+
{
536+
// Smart accounts
537+
var hashToken = jsonObject.SelectToken("$.message.message");
538+
if (hashToken != null)
539+
{
540+
var hashBase64 = hashToken.Value<string>();
541+
var hashBytes = Convert.FromBase64String(hashBase64);
542+
var hashHex = hashBytes.ByteArrayToHexString();
543+
hashToken.Replace(hashHex);
544+
}
545+
}
546+
496547
var messageObject = jsonObject.GetValue("message") as JObject;
497548
foreach (var property in messageObject.Properties())
498549
{
@@ -529,7 +580,7 @@ public async Task<string> RecoverAddress(string message, string signature)
529580
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet)
530581
{
531582
var sw = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
532-
bool isSigValid = await sw.SmartWallet.VerifySignature(signer.HashPrefixedMessage(System.Text.Encoding.UTF8.GetBytes(message)), signature.HexStringToByteArray());
583+
bool isSigValid = await sw.SmartWallet.VerifySignature(message.HashPrefixedMessage().HexStringToByteArray(), signature.HexStringToByteArray());
533584
if (isSigValid)
534585
{
535586
return await GetAddress();

Assets/Thirdweb/Editor/ThirdwebManagerEditor.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ public class ThirdwebManagerEditor : Editor
2727
private SerializedProperty walletConnectExplorerRecommendedWalletIdsProperty;
2828
private SerializedProperty factoryAddressProperty;
2929
private SerializedProperty gaslessProperty;
30-
private SerializedProperty deployOnSignProperty;
3130
private SerializedProperty bundlerUrlProperty;
3231
private SerializedProperty paymasterUrlProperty;
3332
private SerializedProperty entryPointAddressProperty;
@@ -68,7 +67,6 @@ private void OnEnable()
6867
walletConnectExplorerRecommendedWalletIdsProperty = serializedObject.FindProperty("walletConnectExplorerRecommendedWalletIds");
6968
factoryAddressProperty = serializedObject.FindProperty("factoryAddress");
7069
gaslessProperty = serializedObject.FindProperty("gasless");
71-
deployOnSignProperty = serializedObject.FindProperty("deployOnSign");
7270
bundlerUrlProperty = serializedObject.FindProperty("bundlerUrl");
7371
paymasterUrlProperty = serializedObject.FindProperty("paymasterUrl");
7472
entryPointAddressProperty = serializedObject.FindProperty("entryPointAddress");
@@ -306,7 +304,6 @@ public override void OnInspectorGUI()
306304

307305
if (showSmartWalletOptionalFields)
308306
{
309-
EditorGUILayout.PropertyField(deployOnSignProperty);
310307
EditorGUILayout.PropertyField(bundlerUrlProperty);
311308
EditorGUILayout.PropertyField(paymasterUrlProperty);
312309
EditorGUILayout.PropertyField(entryPointAddressProperty);

0 commit comments

Comments
 (0)