Skip to content

Commit e4f27f3

Browse files
authored
Merge branch 'main' into firekeeper/iaw-to-eco
Signed-off-by: Firekeeper <[email protected]>
2 parents 1362405 + ea5254e commit e4f27f3

File tree

10 files changed

+186
-35
lines changed

10 files changed

+186
-35
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup>
4-
<DefaultVersion>2.5.1</DefaultVersion>
4+
<DefaultVersion>2.6.1</DefaultVersion>
55
<DefaultTargetFrameworks>netstandard2.1;net6.0;net7.0;net8.0</DefaultTargetFrameworks>
66
</PropertyGroup>
77

Thirdweb.Console/Program.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,26 @@
9191

9292
#endregion
9393

94+
#region Smart Ecosystem Wallet
95+
96+
// var eco = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Twitch);
97+
// if (!await eco.IsConnected())
98+
// {
99+
// _ = await eco.LoginWithOauth(
100+
// isMobile: false,
101+
// browserOpenAction: (url) =>
102+
// {
103+
// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true };
104+
// _ = Process.Start(psi);
105+
// }
106+
// );
107+
// }
108+
// var smartEco = await SmartWallet.Create(eco, 421614);
109+
// var addy = await smartEco.GetAddress();
110+
// Console.WriteLine($"Smart Ecosystem Wallet address: {addy}");
111+
112+
#endregion
113+
94114
#region Ecosystem Wallet
95115

96116
// var ecosystemWallet = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Telegram);
@@ -329,7 +349,7 @@
329349

330350
#region InAppWallet - OAuth
331351

332-
// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Coinbase);
352+
// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Twitch);
333353
// if (!await inAppWalletOAuth.IsConnected())
334354
// {
335355
// _ = await inAppWalletOAuth.LoginWithOauth(

Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,26 @@ public async Task PrepareTest_NoSig()
102102
Assert.Contains("Method signature not found in contract ABI.", exception.Message);
103103
}
104104

105+
[Fact(Timeout = 120000)]
106+
public async Task ReadTest_TupleIntoArray()
107+
{
108+
var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614);
109+
var result = await contract.Read<List<object>>("getReserves");
110+
Assert.NotNull(result);
111+
Assert.NotEmpty(result);
112+
Assert.True(result.Count == 3);
113+
}
114+
115+
[Fact(Timeout = 120000)]
116+
public async Task ReadTest_TupleIntoList()
117+
{
118+
var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614);
119+
var result = await contract.Read<List<object>>("getReserves");
120+
Assert.NotNull(result);
121+
Assert.NotEmpty(result);
122+
Assert.True(result.Count == 3);
123+
}
124+
105125
private sealed class AllowlistProof
106126
{
107127
public List<byte[]> Proof { get; set; } = new List<byte[]>();

Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,17 @@ public async Task TestRpcError()
7070
Assert.Contains("RPC Error for request", exception.Message);
7171
}
7272

73-
[Fact(Timeout = 120000)]
74-
public async Task TestCache()
75-
{
76-
var client = ThirdwebClient.Create(secretKey: this.SecretKey);
77-
var rpc = ThirdwebRPC.GetRpcInstance(client, 421614);
78-
var blockNumber1 = await rpc.SendRequestAsync<string>("eth_blockNumber");
79-
await ThirdwebTask.Delay(1);
80-
var blockNumber2 = await rpc.SendRequestAsync<string>("eth_blockNumber");
81-
Assert.Equal(blockNumber1, blockNumber2);
82-
await ThirdwebTask.Delay(1000);
83-
var blockNumber3 = await rpc.SendRequestAsync<string>("eth_blockNumber");
84-
Assert.NotEqual(blockNumber1, blockNumber3);
85-
}
73+
// [Fact(Timeout = 120000)]
74+
// public async Task TestCache()
75+
// {
76+
// var client = ThirdwebClient.Create(secretKey: this.SecretKey);
77+
// var rpc = ThirdwebRPC.GetRpcInstance(client, 421614);
78+
// var blockNumber1 = await rpc.SendRequestAsync<string>("eth_blockNumber");
79+
// await ThirdwebTask.Delay(1);
80+
// var blockNumber2 = await rpc.SendRequestAsync<string>("eth_blockNumber");
81+
// Assert.Equal(blockNumber1, blockNumber2);
82+
// await ThirdwebTask.Delay(1000);
83+
// var blockNumber3 = await rpc.SendRequestAsync<string>("eth_blockNumber");
84+
// Assert.NotEqual(blockNumber1, blockNumber3);
85+
// }
8686
}

Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System.Numerics;
2+
using Nethereum.ABI.FunctionEncoding;
3+
using Nethereum.ABI.Model;
24
using Nethereum.Contracts;
35
using Nethereum.Hex.HexTypes;
6+
using Newtonsoft.Json;
47

58
namespace Thirdweb;
69

@@ -119,7 +122,39 @@ public static async Task<T> Read<T>(ThirdwebContract contract, string method, pa
119122
var data = function.GetData(parameters);
120123
var resultData = await rpc.SendRequestAsync<string>("eth_call", new { to = contract.Address, data }, "latest").ConfigureAwait(false);
121124

122-
return function.DecodeTypeOutput<T>(resultData);
125+
if ((typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(List<>)) || typeof(T).IsArray)
126+
{
127+
var functionAbi = contractRaw.ContractBuilder.ContractABI.FindFunctionABIFromInputData(data);
128+
var decoder = new FunctionCallDecoder();
129+
var outputList = new FunctionCallDecoder().DecodeDefaultData(resultData.HexToBytes(), functionAbi.OutputParameters);
130+
var resultList = outputList.Select(x => x.Result).ToList();
131+
132+
if (typeof(T) == typeof(List<object>))
133+
{
134+
return (T)(object)resultList;
135+
}
136+
137+
if (typeof(T) == typeof(object[]))
138+
{
139+
return (T)(object)resultList.ToArray();
140+
}
141+
142+
try
143+
{
144+
var json = JsonConvert.SerializeObject(resultList);
145+
return JsonConvert.DeserializeObject<T>(json);
146+
}
147+
catch (Exception)
148+
{
149+
var dict = outputList.ConvertToObjectDictionary();
150+
var ser = JsonConvert.SerializeObject(dict.First().Value);
151+
return JsonConvert.DeserializeObject<T>(ser);
152+
}
153+
}
154+
else
155+
{
156+
return function.DecodeTypeOutput<T>(resultData);
157+
}
123158
}
124159

125160
/// <summary>

Thirdweb/Thirdweb.Utils/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static class Constants
1919
public const string REDIRECT_HTML =
2020
"<html lang=\"en\" style=\"background-color:#050505;color:#fff\"><body style=\"position:relative;display:flex;flex-direction:column;height:100%;width:100%;margin:0;justify-content:center;align-items:center;text-align:center;overflow:hidden\"><div style=\"position:fixed;top:0;left:50%;background-image:radial-gradient(ellipse at center,hsl(260deg 78% 35% / 40%),transparent 60%);width:2400px;height:1400px;transform:translate(-50%,-50%);z-index:-1\"></div><h1>Authentication Complete!</h1><h2>You may close this tab now and return to the game</h2></body></html>";
2121

22-
internal const string VERSION = "2.5.1";
22+
internal const string VERSION = "2.6.1";
2323
internal const int DEFAULT_FETCH_TIMEOUT = 120000;
2424
internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";
2525
internal const string DUMMY_PAYMASTER_AND_DATA_HEX =

Thirdweb/Thirdweb.Utils/Utils.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,16 @@ public static async Task<bool> IsZkSync(ThirdwebClient client, BigInteger chainI
312312
}
313313
else
314314
{
315-
var chainData = await GetChainMetadata(client, chainId).ConfigureAwait(false);
316-
return !string.IsNullOrEmpty(chainData.StackType) && chainData.StackType.Contains("zksync", StringComparison.OrdinalIgnoreCase);
315+
try
316+
{
317+
var chainData = await GetChainMetadata(client, chainId).ConfigureAwait(false);
318+
return !string.IsNullOrEmpty(chainData.StackType) && chainData.StackType.Contains("zksync", StringComparison.OrdinalIgnoreCase);
319+
}
320+
catch
321+
{
322+
// Assume it is not zkSync if the chain data could not be fetched
323+
return false;
324+
}
317325
}
318326
}
319327

Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Numerics;
12
using Newtonsoft.Json;
23

34
namespace Thirdweb;
@@ -54,4 +55,40 @@ internal class EnclaveSignResponse
5455
[JsonProperty("hash")]
5556
internal string Hash { get; set; }
5657
}
58+
59+
public class EcosystemDetails
60+
{
61+
[JsonProperty("thirdwebAccountId")]
62+
public string ThirdwebAccountId { get; set; }
63+
64+
[JsonProperty("permission")]
65+
public string Permission { get; set; }
66+
67+
[JsonProperty("authOptions")]
68+
public List<string> AuthOptions { get; set; }
69+
70+
[JsonProperty("name")]
71+
public string Name { get; set; }
72+
73+
[JsonProperty("slug")]
74+
public string Slug { get; set; }
75+
76+
[JsonProperty("imageUrl")]
77+
public string ImageUrl { get; set; }
78+
79+
[JsonProperty("smartAccountOptions")]
80+
public EcosystemDetails_SmartAccountOptions? SmartAccountOptions { get; set; }
81+
}
82+
83+
public struct EcosystemDetails_SmartAccountOptions
84+
{
85+
[JsonProperty("chainIds")]
86+
public List<BigInteger> ChainIds { get; set; }
87+
88+
[JsonProperty("sponsorGas")]
89+
public bool SponsorGas { get; set; }
90+
91+
[JsonProperty("accountFactoryAddress")]
92+
public string AccountFactoryAddress { get; set; }
93+
}
5794
}

Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,22 @@ public static async Task<EcosystemWallet> Create(
8282

8383
var authproviderStr = authProvider switch
8484
{
85-
Thirdweb.AuthProvider.Google => "Google",
86-
Thirdweb.AuthProvider.Apple => "Apple",
87-
Thirdweb.AuthProvider.Facebook => "Facebook",
88-
Thirdweb.AuthProvider.JWT => "JWT",
89-
Thirdweb.AuthProvider.AuthEndpoint => "AuthEndpoint",
90-
Thirdweb.AuthProvider.Discord => "Discord",
91-
Thirdweb.AuthProvider.Farcaster => "Farcaster",
92-
Thirdweb.AuthProvider.Telegram => "Telegram",
93-
Thirdweb.AuthProvider.Siwe => "Siwe",
94-
Thirdweb.AuthProvider.Line => "Line",
95-
Thirdweb.AuthProvider.Guest => "Guest",
96-
Thirdweb.AuthProvider.X => "X",
97-
Thirdweb.AuthProvider.Coinbase => "Coinbase",
98-
Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email",
85+
AuthProvider.Google => "Google",
86+
AuthProvider.Apple => "Apple",
87+
AuthProvider.Facebook => "Facebook",
88+
AuthProvider.JWT => "JWT",
89+
AuthProvider.AuthEndpoint => "AuthEndpoint",
90+
AuthProvider.Discord => "Discord",
91+
AuthProvider.Farcaster => "Farcaster",
92+
AuthProvider.Telegram => "Telegram",
93+
AuthProvider.Siwe => "Siwe",
94+
AuthProvider.Line => "Line",
95+
AuthProvider.Guest => "Guest",
96+
AuthProvider.X => "X",
97+
AuthProvider.Coinbase => "Coinbase",
98+
AuthProvider.Github => "Github",
99+
AuthProvider.Twitch => "Twitch",
100+
AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email",
99101
_ => throw new ArgumentException("Invalid AuthProvider"),
100102
};
101103

@@ -276,6 +278,15 @@ public string GetPhoneNumber()
276278
return this.PhoneNumber;
277279
}
278280

281+
public async Task<EcosystemDetails> GetEcosystemDetails()
282+
{
283+
var url = $"{EMBEDDED_WALLET_PATH_2024}/ecosystem-wallet";
284+
var response = await this._httpClient.GetAsync(url).ConfigureAwait(false);
285+
_ = response.EnsureSuccessStatusCode();
286+
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
287+
return JsonConvert.DeserializeObject<EcosystemDetails>(content);
288+
}
289+
279290
#endregion
280291

281292
#region Account Linking
@@ -362,6 +373,8 @@ public async Task<List<LinkedAccount>> LinkAccount(
362373
case "Line":
363374
case "X":
364375
case "Coinbase":
376+
case "Github":
377+
case "Twitch":
365378
serverRes = await ecosystemWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false);
366379
break;
367380
default:

Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ BigInteger erc20PaymasterStorageSlot
123123
public static async Task<SmartWallet> Create(
124124
IThirdwebWallet personalWallet,
125125
BigInteger chainId,
126-
bool gasless = true,
126+
bool? gasless = null,
127127
string factoryAddress = null,
128128
string accountAddressOverride = null,
129129
string entryPoint = null,
@@ -137,10 +137,28 @@ public static async Task<SmartWallet> Create(
137137
throw new InvalidOperationException("SmartAccount.Connect: Personal account must be connected.");
138138
}
139139

140+
if (personalWallet is EcosystemWallet ecoWallet)
141+
{
142+
try
143+
{
144+
var ecoDetails = await ecoWallet.GetEcosystemDetails();
145+
if (ecoDetails.SmartAccountOptions.HasValue)
146+
{
147+
gasless ??= ecoDetails.SmartAccountOptions?.SponsorGas;
148+
factoryAddress ??= string.IsNullOrEmpty(ecoDetails.SmartAccountOptions?.AccountFactoryAddress) ? null : ecoDetails.SmartAccountOptions?.AccountFactoryAddress;
149+
}
150+
}
151+
catch
152+
{
153+
// no-op
154+
}
155+
}
156+
140157
entryPoint ??= Constants.ENTRYPOINT_ADDRESS_V06;
141158

142159
var entryPointVersion = Utils.GetEntryPointVersion(entryPoint);
143160

161+
gasless ??= true;
144162
bundlerUrl ??= $"https://{chainId}.bundler.thirdweb.com/v2";
145163
paymasterUrl ??= $"https://{chainId}.bundler.thirdweb.com/v2";
146164
factoryAddress ??= entryPointVersion == 6 ? Constants.DEFAULT_FACTORY_ADDRESS_V06 : Constants.DEFAULT_FACTORY_ADDRESS_V07;
@@ -180,7 +198,7 @@ public static async Task<SmartWallet> Create(
180198

181199
return new SmartWallet(
182200
personalWallet,
183-
gasless,
201+
gasless.Value,
184202
chainId,
185203
bundlerUrl,
186204
paymasterUrl,

0 commit comments

Comments
 (0)