Skip to content

Commit a73d63c

Browse files
committed
Fix smart wallet signing / email + sw / multithreading
1 parent 08ace58 commit a73d63c

File tree

14 files changed

+112658
-98183
lines changed

14 files changed

+112658
-98183
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private static async Task<RpcResponseMessage> BundlerRequest(string url, string
5252
{
5353
httpRequestMessage.Headers.Add("x-client-id", ThirdwebManager.Instance.SDK.session.Options.clientId);
5454
if (!Utils.IsWebGLBuild())
55-
httpRequestMessage.Headers.Add("x-bundle-id", Utils.GetBundleId());
55+
httpRequestMessage.Headers.Add("x-bundle-id", ThirdwebManager.Instance.SDK.session.BundleId);
5656
}
5757

5858
var httpResponse = await client.SendAsync(httpRequestMessage);

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

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using FactoryContract = Thirdweb.Contracts.AccountFactory.ContractDefinition;
1313
using UnityEngine;
1414
using Nethereum.Contracts;
15+
using Nethereum.Hex.HexConvertors.Extensions;
16+
using Nethereum.Util;
1517

1618
namespace Thirdweb.AccountAbstraction
1719
{
@@ -37,8 +39,19 @@ public class SmartWallet
3739
public Web3 PersonalWeb3 { get; internal set; }
3840
public ThirdwebSDK.SmartWalletConfig Config { get; internal set; }
3941

40-
private bool _initialized;
4142
private bool _deployed;
43+
public bool IsDeployed
44+
{
45+
get { return _deployed; }
46+
}
47+
48+
private bool _deploying;
49+
public bool IsDeploying
50+
{
51+
get { return _deploying; }
52+
}
53+
54+
private bool _initialized;
4255

4356
public SmartWallet(Web3 personalWeb3, ThirdwebSDK.SmartWalletConfig config)
4457
{
@@ -54,6 +67,7 @@ public SmartWallet(Web3 personalWeb3, ThirdwebSDK.SmartWalletConfig config)
5467

5568
_deployed = false;
5669
_initialized = false;
70+
_deploying = false;
5771
}
5872

5973
internal async Task<string> GetPersonalAddress()
@@ -89,6 +103,28 @@ internal async Task UpdateDeploymentStatus()
89103
_deployed = bytecode != "0x";
90104
}
91105

106+
internal async Task ForceDeploy()
107+
{
108+
if (_deployed)
109+
return;
110+
111+
_deploying = true;
112+
var input = new TransactionInput("0x", Accounts[0], new HexBigInteger(0));
113+
var txHash = await Request(new RpcRequestMessage(1, "eth_sendTransaction", input));
114+
await Transaction.WaitForTransactionResult(txHash.Result.ToString());
115+
await UpdateDeploymentStatus();
116+
_deploying = false;
117+
}
118+
119+
internal async Task<bool> VerifySignature(byte[] hash, byte[] signature)
120+
{
121+
var verifyRes = await TransactionManager.ThirdwebRead<AccountContract.IsValidSignatureFunction, AccountContract.IsValidSignatureOutputDTO>(
122+
Accounts[0],
123+
new AccountContract.IsValidSignatureFunction() { Hash = hash, Signature = signature }
124+
);
125+
return verifyRes.MagicValue.ToHex(true) == new byte[] { 0x16, 0x26, 0xba, 0x7e }.ToHex(true);
126+
}
127+
92128
internal async Task<(byte[] initCode, BigInteger gas)> GetInitCode()
93129
{
94130
if (_deployed)
@@ -153,7 +189,7 @@ private async Task<RpcResponseMessage> CreateUserOpAndSend(RpcRequestMessage req
153189
Nonce = await GetNonce(),
154190
InitCode = initData.initCode,
155191
CallData = executeInput.Data.HexStringToByteArray(),
156-
CallGasLimit = transactionInput.Gas.Value,
192+
CallGasLimit = transactionInput.Gas != null ? (transactionInput.Gas.Value < 21000 ? 100000 : transactionInput.Gas.Value) : 100000,
157193
VerificationGasLimit = 100000 + initData.gas,
158194
PreVerificationGas = 21000,
159195
MaxFeePerGas = latestBlock.BaseFeePerGas.Value * 2 + BigInteger.Parse("1500000000"),
@@ -164,13 +200,8 @@ private async Task<RpcResponseMessage> CreateUserOpAndSend(RpcRequestMessage req
164200
partialUserOp.PreVerificationGas = partialUserOp.CalcPreVerificationGas();
165201
var partialUserOpHexified = partialUserOp.EncodeUserOperation();
166202

167-
// Update gas estimates and paymaster data if any
168-
169-
var gasEstimates = await BundlerClient.EthEstimateUserOperationGas(Config.bundlerUrl, apiKey, requestMessage.Id, partialUserOpHexified, Config.entryPointAddress);
203+
// Update paymaster data if any
170204

171-
partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value;
172-
partialUserOp.CallGasLimit = new HexBigInteger(gasEstimates.CallGasLimit).Value;
173-
partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGas).Value;
174205
partialUserOp.PaymasterAndData = await GetPaymasterAndData(requestMessage.Id, partialUserOpHexified, apiKey);
175206

176207
// Hash, sign and encode the user operation
@@ -188,7 +219,7 @@ private async Task<RpcResponseMessage> CreateUserOpAndSend(RpcRequestMessage req
188219
// Wait for the transaction to be mined
189220

190221
string txHash = null;
191-
while (txHash == null && Application.isPlaying)
222+
while (txHash == null)
192223
{
193224
var getUserOpResponse = await BundlerClient.EthGetUserOperationByHash(Config.bundlerUrl, apiKey, requestMessage.Id, userOpHash);
194225
txHash = getUserOpResponse?.transactionHash;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public static async Task<byte[]> HashAndSignUserOp(this EntryPointContract.UserO
1515
);
1616

1717
var smartWallet = ThirdwebManager.Instance.SDK.session.ActiveWallet;
18-
if (smartWallet.GetSignerProvider() == WalletProvider.LocalWallet)
18+
if (smartWallet.GetLocalAccount() != null)
1919
{
2020
var localWallet = smartWallet.GetLocalAccount();
2121
return new EthereumMessageSigner().Sign(userOpHash.ReturnValue1, new EthECKey(localWallet.PrivateKey)).HexStringToByteArray();

Assets/Thirdweb/Core/Scripts/Storage/StorageUploader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task<IPFSUploadResult> UploadFromPath(string path)
4545
{
4646
pinReq.SetRequestHeader("x-client-id", ThirdwebManager.Instance.SDK.storage.ClientId);
4747
if (!Utils.IsWebGLBuild())
48-
pinReq.SetRequestHeader("x-bundle-id", Utils.GetBundleId());
48+
pinReq.SetRequestHeader("x-bundle-id", ThirdwebManager.Instance.SDK.session.BundleId);
4949

5050
await pinReq.SendWebRequest();
5151

Assets/Thirdweb/Core/Scripts/ThirdwebInterceptor.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Threading.Tasks;
33
using Nethereum.JsonRpc.Client;
44
using Nethereum.Signer;
5-
using Newtonsoft.Json;
65
using Thirdweb.Wallets;
76

87
namespace Thirdweb

Assets/Thirdweb/Core/Scripts/ThirdwebSession.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public class ThirdwebSession
2929

3030
public static int Nonce = 0;
3131

32+
public string BundleId { get; private set; }
33+
3234
#endregion
3335

3436
#region Constructors
@@ -41,6 +43,7 @@ public ThirdwebSession(ThirdwebSDK.Options options, BigInteger chainId, string r
4143
SiweSession = new SiweMessageService();
4244
Web3 = new Web3(rpcUrl);
4345
CurrentChainData = options.supportedChains.ToList().Find(x => x.chainId == new HexBigInteger(chainId).HexValue);
46+
BundleId = Utils.GetBundleId();
4447
}
4548

4649
#endregion

Assets/Thirdweb/Core/Scripts/Utils.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,10 @@ public static string GetBundleId()
388388

389389
public static string AppendBundleIdQueryParam(this string uri)
390390
{
391-
string bundleId = GetBundleId();
392-
if (!Utils.IsWebGLBuild())
393-
uri += $"?bundleId={bundleId}";
391+
if (Utils.IsWebGLBuild())
392+
return uri;
393+
394+
uri += $"?bundleId={ThirdwebManager.Instance?.SDK?.session?.BundleId ?? GetBundleId()}";
394395
return uri;
395396
}
396397

Assets/Thirdweb/Core/Scripts/Wallet.cs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public async Task<LoginPayload> Authenticate(string domain)
9696
Resources = new List<string>(),
9797
Uri = $"https://{domain}",
9898
Statement = "Please ensure that the domain above matches the URL of the current website.",
99-
Address = await GetSignerAddress(),
99+
Address = await GetAddress(),
100100
Domain = domain,
101101
ChainId = (await GetChainId()).ToString(),
102102
Version = "1",
@@ -166,9 +166,13 @@ public async Task<string> Verify(LoginPayload payload)
166166
};
167167
var signature = payload.signature;
168168
var validUser = await siwe.IsUserAddressRegistered(siweMessage);
169+
var msg = SiweMessageStringBuilder.BuildMessage(siweMessage);
169170
if (validUser)
170171
{
171-
if (await siwe.IsMessageSignatureValid(siweMessage, signature))
172+
string recoveredAddress = await RecoverAddress(msg, signature);
173+
Debug.Log($"Recovered address: {recoveredAddress}");
174+
Debug.Log($"Message address: {siweMessage.Address}");
175+
if (recoveredAddress == siweMessage.Address)
172176
{
173177
if (siwe.IsMessageTheSameAsSessionStored(siweMessage))
174178
{
@@ -376,12 +380,25 @@ public async Task<TransactionResult> Transfer(string to, string amount, string c
376380
/// <returns>The signature of the message as a string.</returns>
377381
public async Task<string> Sign(string message)
378382
{
383+
if (!await IsConnected())
384+
throw new Exception("No account connected!");
385+
379386
if (Utils.IsWebGLBuild())
380387
{
381388
return await Bridge.InvokeRoute<string>(getRoute("sign"), Utils.ToJsonStringArray(message));
382389
}
383390
else
384391
{
392+
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet)
393+
{
394+
var sw = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
395+
if (!sw.SmartWallet.IsDeployed && !sw.SmartWallet.IsDeploying)
396+
{
397+
Debug.Log("SmartWallet not deployed, deploying before signing...");
398+
await sw.SmartWallet.ForceDeploy();
399+
}
400+
}
401+
385402
return await ThirdwebManager.Instance.SDK.session.Request<string>("personal_sign", message, await GetSignerAddress());
386403
}
387404
}
@@ -397,7 +414,20 @@ public async Task<string> Sign(string message)
397414
public async Task<string> SignTypedDataV4<T, TDomain>(T data, TypedData<TDomain> typedData)
398415
where TDomain : IDomain
399416
{
400-
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetSignerProvider() == WalletProvider.LocalWallet)
417+
if (!await IsConnected())
418+
throw new Exception("No account connected!");
419+
420+
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet)
421+
{
422+
var sw = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
423+
if (!sw.SmartWallet.IsDeployed && !sw.SmartWallet.IsDeploying)
424+
{
425+
Debug.Log("SmartWallet not deployed, deploying before signing...");
426+
await sw.SmartWallet.ForceDeploy();
427+
}
428+
}
429+
430+
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetLocalAccount() != null)
401431
{
402432
var signer = new Eip712TypedDataSigner();
403433
var key = new EthECKey(ThirdwebManager.Instance.SDK.session.ActiveWallet.GetLocalAccount().PrivateKey);
@@ -441,6 +471,15 @@ public async Task<string> RecoverAddress(string message, string signature)
441471
else
442472
{
443473
var signer = new EthereumMessageSigner();
474+
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() == WalletProvider.SmartWallet)
475+
{
476+
var sw = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
477+
bool isSigValid = await sw.SmartWallet.VerifySignature(signer.HashPrefixedMessage(System.Text.Encoding.UTF8.GetBytes(message)), signature.HexStringToByteArray());
478+
if (isSigValid)
479+
{
480+
return await GetAddress();
481+
}
482+
}
444483
var addressRecovered = signer.EncodeUTF8AndEcRecover(message, signature);
445484
return addressRecovered;
446485
}
@@ -463,9 +502,9 @@ public async Task<TransactionResult> SendRawTransaction(TransactionRequest trans
463502
transactionRequest.data,
464503
transactionRequest.to,
465504
transactionRequest.from,
466-
new Nethereum.Hex.HexTypes.HexBigInteger(BigInteger.Parse(transactionRequest.gasLimit)),
467-
new Nethereum.Hex.HexTypes.HexBigInteger(BigInteger.Parse(transactionRequest.gasPrice)),
468-
new Nethereum.Hex.HexTypes.HexBigInteger(transactionRequest.value)
505+
new HexBigInteger(BigInteger.Parse(transactionRequest.gasLimit)),
506+
new HexBigInteger(BigInteger.Parse(transactionRequest.gasPrice)),
507+
new HexBigInteger(transactionRequest.value)
469508
);
470509
var receipt = await ThirdwebManager.Instance.SDK.session.Web3.Eth.TransactionManager.SendTransactionAndWaitForReceiptAsync(input);
471510
return receipt.ToTransactionResult();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public async Task<string> Connect(WalletConnection walletConnection, string rpc)
3131
}
3232

3333
_account = (await PaperUI.Instance.Connect(_paper, walletConnection.email)).Account;
34-
_web3 = new Web3(_account, ThirdwebManager.Instance.SDK.session.RPC);
34+
_web3 = new Web3(_account, rpc);
3535

3636
return await GetAddress();
3737
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ namespace Thirdweb.Wallets
88
{
99
public class ThirdwebSmartWallet : IThirdwebWallet
1010
{
11+
private SmartWallet _smartWallet;
12+
public SmartWallet SmartWallet
13+
{
14+
get { return _smartWallet; }
15+
}
16+
1117
private Web3 _web3;
1218
private WalletProvider _provider;
1319
private WalletProvider _signerProvider;
1420
private IThirdwebWallet _personalWallet;
15-
private SmartWallet _smartWallet;
1621
private ThirdwebSDK.SmartWalletConfig _config;
1722

1823
public ThirdwebSmartWallet(IThirdwebWallet personalWallet, ThirdwebSDK.SmartWalletConfig config)

0 commit comments

Comments
 (0)