Skip to content

Commit 42d4c9b

Browse files
authored
Ecosystem Wallets (#59)
1 parent 22f390d commit 42d4c9b

File tree

25 files changed

+1061
-469
lines changed

25 files changed

+1061
-469
lines changed

.editorconfig

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ dotnet_style_prefer_auto_properties = true:warning
4747
dotnet_style_prefer_conditional_expression_over_assignment = true:warning
4848
dotnet_style_prefer_conditional_expression_over_return = true:warning
4949

50+
# Code Quality
51+
dotnet_code_quality_unused_parameters = all:warning
52+
5053
# Namespace preferences
5154
csharp_style_namespace_declarations = file_scoped:warning
5255

Thirdweb.Console/Program.cs

+39-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#pragma warning disable IDE0005
22
#pragma warning disable IDE0059
33

4-
using Thirdweb;
5-
using dotenv.net;
64
using System.Diagnostics;
7-
using Thirdweb.Pay;
8-
using Newtonsoft.Json;
9-
using Nethereum.Hex.HexTypes;
105
using System.Numerics;
6+
using dotenv.net;
7+
using Nethereum.Hex.HexTypes;
8+
using Newtonsoft.Json;
119
using Newtonsoft.Json.Linq;
10+
using Thirdweb;
11+
using Thirdweb.Pay;
1212

1313
DotEnv.Load();
1414

@@ -72,6 +72,40 @@
7272

7373
#endregion
7474

75+
#region Ecosystem Wallet
76+
77+
var ecosystemWallet = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", email: "[email protected]");
78+
79+
if (!await ecosystemWallet.IsConnected())
80+
{
81+
_ = await ecosystemWallet.SendOTP();
82+
Console.WriteLine("Enter OTP:");
83+
var otp = Console.ReadLine();
84+
_ = await ecosystemWallet.LoginWithOtp(otp);
85+
}
86+
var ecosystemWalletAddress = await ecosystemWallet.GetAddress();
87+
Console.WriteLine($"Ecosystem Wallet address: {ecosystemWalletAddress}");
88+
89+
var ecosystemPersonalSignature = await ecosystemWallet.PersonalSign("Hello, Thirdweb!");
90+
Console.WriteLine($"Ecosystem Wallet personal sign: {ecosystemPersonalSignature}");
91+
var isValidPersonal = (await ecosystemWallet.RecoverAddressFromPersonalSign("Hello, Thirdweb!", ecosystemPersonalSignature)) == ecosystemWalletAddress;
92+
Console.WriteLine($"Ecosystem Wallet personal sign valid: {isValidPersonal}");
93+
94+
var ecosystemTypedSignature = await ecosystemWallet.SignTypedDataV4(
95+
/*lang=json,strict*/
96+
"{\"types\": {\"EIP712Domain\": [{\"name\": \"name\",\"type\": \"string\"},{\"name\": \"version\",\"type\": \"string\"},{\"name\": \"chainId\",\"type\": \"uint256\"},{\"name\": \"verifyingContract\",\"type\": \"address\"}],\"Person\": [{\"name\": \"name\",\"type\": \"string\"},{\"name\": \"wallet\",\"type\": \"address\"}],\"Mail\": [{\"name\": \"from\",\"type\": \"Person\"},{\"name\": \"to\",\"type\": \"Person\"},{\"name\": \"contents\",\"type\": \"string\"}]},\"primaryType\": \"Mail\",\"domain\": {\"name\": \"Ether Mail\",\"version\": \"1\",\"chainId\": 1,\"verifyingContract\": \"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\": {\"from\": {\"name\": \"Cow\",\"wallet\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\": {\"name\": \"Bob\",\"wallet\": \"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\": \"Hello, Bob!\"}}"
97+
);
98+
Console.WriteLine($"Ecosystem Wallet typed sign: {ecosystemTypedSignature}");
99+
100+
// var ecosystemSmartWallet = await SmartWallet.Create(ecosystemWallet, 421614);
101+
102+
// var ecosystemTx = await ThirdwebTransaction.Create(wallet: ecosystemSmartWallet, txInput: new ThirdwebTransactionInput(chainId: 421614, to: await ecosystemWallet.GetAddress()));
103+
104+
// var ecosystemTxHash = await ThirdwebTransaction.Send(ecosystemTx);
105+
// Console.WriteLine($"Ecosystem Wallet transaction hash: {ecosystemTxHash}");
106+
107+
#endregion
108+
75109
#region Maximum low level zksync tx
76110

77111
// var chainId = 300;
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Numerics;
2-
using System.Reflection;
32

43
namespace Thirdweb.Tests.RPC;
54

@@ -34,24 +33,6 @@ public async Task TestTimeout()
3433
_ = await Assert.ThrowsAsync<TimeoutException>(async () => await rpc.SendRequestAsync<string>("eth_chainId"));
3534
}
3635

37-
[Fact(Timeout = 120000)]
38-
public async Task TestBatch()
39-
{
40-
var client = ThirdwebClient.Create(secretKey: this.SecretKey);
41-
var rpc = ThirdwebRPC.GetRpcInstance(client, 1);
42-
var req = rpc.SendRequestAsync<string>("eth_blockNumber");
43-
_ = await rpc.SendRequestAsync<string>("eth_chainId");
44-
var blockNumberTasks = new List<Task<string>>();
45-
for (var i = 0; i < 100; i++)
46-
{
47-
blockNumberTasks.Add(rpc.SendRequestAsync<string>("eth_blockNumber"));
48-
}
49-
var results = await Task.WhenAll(blockNumberTasks);
50-
Assert.Equal(100, results.Length);
51-
Assert.All(results, result => Assert.StartsWith("0x", result));
52-
Assert.All(results, result => Assert.Equal(results[0], result));
53-
}
54-
5536
[Fact(Timeout = 120000)]
5637
public async Task TestDeserialization()
5738
{
@@ -95,65 +76,8 @@ public async Task TestCache()
9576
var client = ThirdwebClient.Create(secretKey: this.SecretKey);
9677
var rpc = ThirdwebRPC.GetRpcInstance(client, 1);
9778
var blockNumber1 = await rpc.SendRequestAsync<string>("eth_blockNumber");
98-
await Task.Delay(100);
79+
await ThirdwebTask.Delay(100);
9980
var blockNumber2 = await rpc.SendRequestAsync<string>("eth_blockNumber");
10081
Assert.Equal(blockNumber1, blockNumber2);
10182
}
102-
103-
[Fact(Timeout = 120000)]
104-
public async Task TestBatchSizeLimit()
105-
{
106-
var client = ThirdwebClient.Create(secretKey: this.SecretKey);
107-
var rpc = ThirdwebRPC.GetRpcInstance(client, 1);
108-
var blockNumberTasks = new List<Task<string>>();
109-
for (var i = 0; i < 101; i++)
110-
{
111-
blockNumberTasks.Add(rpc.SendRequestAsync<string>("eth_blockNumber"));
112-
}
113-
var results = await Task.WhenAll(blockNumberTasks);
114-
Assert.Equal(101, results.Length);
115-
Assert.All(results, result => Assert.StartsWith("0x", result));
116-
}
117-
118-
[Fact(Timeout = 120000)]
119-
public void Timer_StartsAndStops()
120-
{
121-
var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100));
122-
timer.Start();
123-
Assert.True(IsTimerRunning(timer));
124-
125-
timer.Stop();
126-
Assert.False(IsTimerRunning(timer));
127-
}
128-
129-
[Fact(Timeout = 120000)]
130-
public async Task Timer_ElapsedEventFires()
131-
{
132-
var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100));
133-
var eventFired = false;
134-
135-
timer.Elapsed += () => eventFired = true;
136-
timer.Start();
137-
138-
await Task.Delay(200); // Wait for the timer to elapse at least once
139-
Assert.True(eventFired);
140-
141-
timer.Stop();
142-
}
143-
144-
[Fact(Timeout = 120000)]
145-
public void Timer_DisposeStopsTimer()
146-
{
147-
var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100));
148-
timer.Start();
149-
timer.Dispose();
150-
Assert.False(IsTimerRunning(timer));
151-
}
152-
153-
private static bool IsTimerRunning(ThirdwebRPCTimer timer)
154-
{
155-
var fieldInfo = typeof(ThirdwebRPCTimer).GetField("_isRunning", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException("The field '_isRunning' was not found.");
156-
var value = fieldInfo.GetValue(timer);
157-
return value == null ? throw new InvalidOperationException("The field '_isRunning' value is null.") : (bool)value;
158-
}
15983
}

Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs

-12
Original file line numberDiff line numberDiff line change
@@ -441,18 +441,6 @@ public async Task WaitForTransactionReceipt_CancellationToken()
441441
var aaFailedReceipt = await Assert.ThrowsAsync<Exception>(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHash, cts.Token));
442442
Assert.StartsWith($"Transaction {aaSilentRevertTxHash} execution silently reverted", aaFailedReceipt.Message);
443443

444-
var infiniteTxHash = "0x55181384a4b908ddf6311cf0eb55ea0aa2b1ef4d9e0cc047eab9051fec284958";
445-
cts = new CancellationTokenSource();
446-
cts.CancelAfter(1);
447-
var infiniteReceipt = await Assert.ThrowsAsync<Exception>(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, infiniteTxHash, cts.Token));
448-
Assert.Equal($"Transaction receipt polling for hash {infiniteTxHash} was cancelled.", infiniteReceipt.Message);
449-
450-
cts = new CancellationTokenSource();
451-
var infiniteReceipt2 = Assert.ThrowsAsync<Exception>(() => ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, infiniteTxHash, cts.Token));
452-
await Task.Delay(2000);
453-
cts.Cancel();
454-
Assert.Equal($"Transaction receipt polling for hash {infiniteTxHash} was cancelled.", (await infiniteReceipt2).Message);
455-
456444
var aaReceipt2 = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaTxHash, CancellationToken.None);
457445
Assert.NotNull(aaReceipt2);
458446
}

Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Thirdweb;
77
/// </summary>
88
public class ThirdwebHttpContent
99
{
10-
private readonly byte[] content;
10+
private readonly byte[] _content;
1111

1212
/// <summary>
1313
/// Initializes a new instance of the <see cref="ThirdwebHttpContent"/> class from a string.
@@ -21,7 +21,7 @@ public ThirdwebHttpContent(string content)
2121
throw new ArgumentNullException(nameof(content));
2222
}
2323

24-
this.content = Encoding.UTF8.GetBytes(content);
24+
this._content = Encoding.UTF8.GetBytes(content);
2525
}
2626

2727
/// <summary>
@@ -31,7 +31,7 @@ public ThirdwebHttpContent(string content)
3131
/// <exception cref="ArgumentNullException">Thrown if the content is null.</exception>
3232
public ThirdwebHttpContent(byte[] content)
3333
{
34-
this.content = content ?? throw new ArgumentNullException(nameof(content));
34+
this._content = content ?? throw new ArgumentNullException(nameof(content));
3535
}
3636

3737
/// <summary>
@@ -48,7 +48,7 @@ public ThirdwebHttpContent(Stream content)
4848

4949
using var memoryStream = new MemoryStream();
5050
content.CopyTo(memoryStream);
51-
this.content = memoryStream.ToArray();
51+
this._content = memoryStream.ToArray();
5252
}
5353

5454
/// <summary>
@@ -57,7 +57,7 @@ public ThirdwebHttpContent(Stream content)
5757
/// <returns>A task that represents the asynchronous operation. The task result contains the content string.</returns>
5858
public Task<string> ReadAsStringAsync()
5959
{
60-
return Task.FromResult(Encoding.UTF8.GetString(this.content));
60+
return Task.FromResult(Encoding.UTF8.GetString(this._content));
6161
}
6262

6363
/// <summary>
@@ -66,7 +66,7 @@ public Task<string> ReadAsStringAsync()
6666
/// <returns>A task that represents the asynchronous operation. The task result contains the content byte array.</returns>
6767
public Task<byte[]> ReadAsByteArrayAsync()
6868
{
69-
return Task.FromResult(this.content);
69+
return Task.FromResult(this._content);
7070
}
7171

7272
/// <summary>
@@ -75,7 +75,7 @@ public Task<byte[]> ReadAsByteArrayAsync()
7575
/// <returns>A task that represents the asynchronous operation. The task result contains the content stream.</returns>
7676
public Task<Stream> ReadAsStreamAsync()
7777
{
78-
var stream = new MemoryStream(this.content);
78+
var stream = new MemoryStream(this._content);
7979
return Task.FromResult<Stream>(stream);
8080
}
8181
}

Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs

+14-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Thirdweb;
1010
public class ThirdwebRPC : IDisposable
1111
{
1212
private const int BatchSizeLimit = 100;
13-
private readonly TimeSpan _batchInterval = TimeSpan.FromMilliseconds(100);
13+
private readonly TimeSpan _batchInterval = TimeSpan.FromMilliseconds(50);
1414

1515
private readonly Uri _rpcUrl;
1616
private readonly TimeSpan _rpcTimeout;
@@ -21,7 +21,7 @@ public class ThirdwebRPC : IDisposable
2121
private readonly object _batchLock = new();
2222
private readonly object _responseLock = new();
2323
private readonly object _cacheLock = new();
24-
private readonly ThirdwebRPCTimer _batchTimer;
24+
private readonly CancellationTokenSource _cancellationTokenSource = new();
2525

2626
private int _requestIdCounter = 1;
2727

@@ -159,9 +159,7 @@ private ThirdwebRPC(ThirdwebClient client, BigInteger chainId)
159159
this._httpClient = client.HttpClient;
160160
this._rpcUrl = new Uri($"https://{chainId}.rpc.thirdweb.com/");
161161
this._rpcTimeout = TimeSpan.FromMilliseconds(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc));
162-
this._batchTimer = new ThirdwebRPCTimer(this._batchInterval);
163-
this._batchTimer.Elapsed += this.SendBatchNow;
164-
this._batchTimer.Start();
162+
_ = this.StartBackgroundFlushAsync();
165163
}
166164

167165
private void SendBatchNow()
@@ -278,8 +276,18 @@ private static string GetCacheKey(string method, params object[] parameters)
278276
return keyBuilder.ToString();
279277
}
280278

279+
private async Task StartBackgroundFlushAsync()
280+
{
281+
while (!this._cancellationTokenSource.Token.IsCancellationRequested)
282+
{
283+
await ThirdwebTask.Delay(this._batchInterval.Milliseconds, this._cancellationTokenSource.Token).ConfigureAwait(false);
284+
this.SendBatchNow();
285+
}
286+
}
287+
281288
public void Dispose()
282289
{
283-
throw new NotImplementedException();
290+
this._cancellationTokenSource.Cancel();
291+
this._cancellationTokenSource.Dispose();
284292
}
285293
}

Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs

-79
This file was deleted.

0 commit comments

Comments
 (0)