From c16c487d3e8313ed0d56244ce1fa579f63a82cda Mon Sep 17 00:00:00 2001 From: rob1997 Date: Fri, 24 May 2024 13:54:00 +0300 Subject: [PATCH 01/10] added/implemented WalletSigner and IWalletConfig Next Steps, Add signing check and address validity check --- .../Web3/Evm/Wallet/IWalletConfig.cs | 9 ++++ .../Evm/Wallet/WalletProviderExtensions.cs | 32 ++++++++++++++ .../Web3/Evm/Wallet/WalletSigner.cs | 44 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletConfig.cs create mode 100644 src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs create mode 100644 src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletConfig.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletConfig.cs new file mode 100644 index 000000000..24f231c3f --- /dev/null +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletConfig.cs @@ -0,0 +1,9 @@ +namespace ChainSafe.Gaming.Web3.Evm.Wallet +{ + public interface IWalletConfig + { + public string SignMessageRpcMethodName { get; } + + public string SignTypedMessageRpcMethodName { get; } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs new file mode 100644 index 000000000..a08ec294d --- /dev/null +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs @@ -0,0 +1,32 @@ +using ChainSafe.Gaming.Evm.Signers; +using ChainSafe.Gaming.Web3.Build; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace ChainSafe.Gaming.Web3.Evm.Wallet +{ + public static class WalletProviderExtensions + { + internal static IWeb3ServiceCollection UseWalletProvider(this IWeb3ServiceCollection collection, IWalletConfig config) + where TProvider : WalletProvider + { + collection.AssertServiceNotBound(); + + collection.AddSingleton(); + + collection.Replace(ServiceDescriptor.Singleton(typeof(IWalletConfig), config)); + + return collection; + } + + internal static IWeb3ServiceCollection UseWalletSigner(this IWeb3ServiceCollection collection) + where TSigner : WalletSigner + { + collection.AssertServiceNotBound(); + + collection.AddSingleton(); + + return collection; + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs new file mode 100644 index 000000000..45969288e --- /dev/null +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using ChainSafe.Gaming.Evm.Signers; +using ChainSafe.Gaming.Web3.Core; +using ChainSafe.Gaming.Web3.Core.Evm; + +namespace ChainSafe.Gaming.Web3.Evm.Wallet +{ + public class WalletSigner : ISigner, ILifecycleParticipant + { + private readonly IWalletProvider walletProvider; + private readonly IWalletConfig walletConfig; + + public WalletSigner(IWalletProvider walletProvider, IWalletConfig walletConfig) + { + this.walletProvider = walletProvider; + this.walletConfig = walletConfig; + } + + public string PublicAddress { get; private set; } + + public virtual async ValueTask WillStartAsync() + { + PublicAddress = await walletProvider.Connect(); + } + + public virtual Task SignMessage(string message) + { + return walletProvider.Perform(walletConfig.SignMessageRpcMethodName, message, PublicAddress); + } + + public virtual Task SignTypedData(SerializableDomain domain, TStructType message) + { + SerializableTypedData typedData = new SerializableTypedData(domain, message); + + // MetaMask doesn't work with regular eth_signTypedData method, has to be eth_signTypedData_v4. + return walletProvider.Perform(walletConfig.SignTypedMessageRpcMethodName, typedData, PublicAddress); + } + + public virtual async ValueTask WillStopAsync() + { + await walletProvider.Disconnect(); + } + } +} \ No newline at end of file From 7da80fe8b7bdad411841160459e48a172d655848 Mon Sep 17 00:00:00 2001 From: rob1997 Date: Fri, 24 May 2024 17:12:30 +0300 Subject: [PATCH 02/10] all WalletSigner signs now verified, HyperPlay now uses WalletSigner --- .../HyperPlayConfig.cs | 11 +++ .../HyperPlayExtensions.cs | 23 +---- .../HyperPlayProvider.cs | 17 +--- .../HyperPlaySigner.cs | 61 ------------ .../Web3/Core/Debug/AddressExtensions.cs | 12 ++- .../Web3/Core/Debug/HashExtensions.cs | 97 +++++++++++++++++++ ...lletConfig.cs => IWalletProviderConfig.cs} | 2 +- .../Evm/Wallet/WalletProviderExtensions.cs | 10 +- .../Web3/Evm/Wallet/WalletSigner.cs | 22 +++-- .../Scripts/Scenes/HyperPlayLoginProvider.cs | 2 +- 10 files changed, 142 insertions(+), 115 deletions(-) create mode 100644 src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs delete mode 100644 src/ChainSafe.Gaming.HyperPlay/HyperPlaySigner.cs create mode 100644 src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs rename src/ChainSafe.Gaming/Web3/Evm/Wallet/{IWalletConfig.cs => IWalletProviderConfig.cs} (80%) diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs new file mode 100644 index 000000000..e1ea735a4 --- /dev/null +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs @@ -0,0 +1,11 @@ +using ChainSafe.Gaming.Web3.Evm.Wallet; + +namespace ChainSafe.Gaming.HyperPlay +{ + public class HyperPlayConfig : IWalletProviderConfig + { + public string SignMessageRpcMethodName => "personal_sign"; + + public string SignTypedMessageRpcMethodName => "eth_signTypedData_v3"; + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs index b71c3671d..b15e0c403 100644 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs @@ -13,28 +13,13 @@ public static class HyperPlayExtensions /// Binds implementation of as to Web3 as a service. /// /// Service collection to bind implementations to. + /// Config for wallet provider. /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection collection) + public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection collection, HyperPlayConfig config = null) { - collection.AssertServiceNotBound(); + config ??= new HyperPlayConfig(); - collection.AddSingleton(); - - return collection; - } - - /// - /// Binds implementation of as to Web3 as a service. - /// - /// Service collection to bind implementations to. - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseHyperPlaySigner(this IWeb3ServiceCollection collection) - { - collection.AssertServiceNotBound(); - - collection.AddSingleton(); - - return collection; + return collection.UseWalletProvider(config).UseWalletSigner(); } /// diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayProvider.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayProvider.cs index 8cb8186ad..bae149c01 100644 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayProvider.cs +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayProvider.cs @@ -42,26 +42,13 @@ public override async Task Connect() { string[] accounts = await Perform("eth_accounts"); - string account = accounts[0].AssertIsPublicAddress(nameof(account)); + string account = accounts[0]; string message = "Sign-in with Ethereum"; string hash = await Perform("personal_sign", message, account); - // Verify signature. - // TODO: Make into a Util Method. - EthECDSASignature signature = MessageSigner.ExtractEcdsaSignature(hash); - - string messageToHash = "\x19" + "Ethereum Signed Message:\n" + message.Length + message; - - byte[] messageHash = new Sha3Keccack().CalculateHash(Encoding.UTF8.GetBytes(messageToHash)); - - var key = EthECKey.RecoverFromSignature(signature, messageHash); - - if (key.GetPublicAddress().ToLower().Trim() != account.ToLower().Trim()) - { - throw new Web3Exception("Fetched address does not match the signing address."); - } + hash.AssertSignatureValid(message, account); return account; } diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlaySigner.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlaySigner.cs deleted file mode 100644 index fed910337..000000000 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlaySigner.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading.Tasks; -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Web3.Core; -using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Evm.Wallet; - -namespace ChainSafe.Gaming.HyperPlay -{ - /// - /// Concrete implementation of via HyperPlay desktop client. - /// - public class HyperPlaySigner : ISigner, ILifecycleParticipant - { - private readonly IWalletProvider walletProvider; - - /// - /// Initializes a new instance of the class. - /// - /// HyperPlay connection provider to connect and make RPC requests. - public HyperPlaySigner(IWalletProvider walletProvider) - { - this.walletProvider = walletProvider; - } - - public string PublicAddress { get; private set; } - - public async ValueTask WillStartAsync() - { - PublicAddress = await walletProvider.Connect(); - } - - /// - /// Sign message via HyperPlay desktop client. - /// - /// Message to sign. - /// Signed message hash. - public Task SignMessage(string message) - { - return walletProvider.Perform("personal_sign", message, PublicAddress); - } - - /// - /// Sign typed data via HyperPlay desktop client. - /// - /// A serializable domain separator. - /// Data to be signed. - /// Data type of data to be signed. - /// Hash response of a successfully signed typed data. - public Task SignTypedData(SerializableDomain domain, TStructType message) - { - SerializableTypedData typedData = new SerializableTypedData(domain, message); - - return walletProvider.Perform("eth_signTypedData_v3", PublicAddress, typedData); - } - - public ValueTask WillStopAsync() - { - return new ValueTask(Task.CompletedTask); - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Core/Debug/AddressExtensions.cs b/src/ChainSafe.Gaming/Web3/Core/Debug/AddressExtensions.cs index e914a3c04..74d2aaae3 100644 --- a/src/ChainSafe.Gaming/Web3/Core/Debug/AddressExtensions.cs +++ b/src/ChainSafe.Gaming/Web3/Core/Debug/AddressExtensions.cs @@ -1,3 +1,5 @@ +using System.Text.RegularExpressions; + namespace ChainSafe.Gaming.Web3.Core.Debug { public static class AddressExtensions @@ -9,22 +11,22 @@ public static class AddressExtensions /// True if the string provided is a public address. public static bool IsPublicAddress(string value) { - // TODO: more accurate test/Regex - return !string.IsNullOrEmpty(value) && value.Length == 42; + string regexPattern = @"^0x[a-fA-F0-9]{40}$"; + + return !string.IsNullOrEmpty(value) && Regex.IsMatch(value, regexPattern); } /// /// Assert that the string provided is a public address. /// /// String to check. - /// Name of the string variable (nameof). /// String that was checked. /// The string provided is not public address. - public static string AssertIsPublicAddress(this string value, string variableName) + public static string AssertIsPublicAddress(this string value) { if (!IsPublicAddress(value)) { - throw new Web3AssertionException($"\"{variableName}\" is not a public address."); + throw new Web3AssertionException($"\"{value}\" is not a public address."); } return value; diff --git a/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs b/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs new file mode 100644 index 000000000..a7cd15205 --- /dev/null +++ b/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs @@ -0,0 +1,97 @@ +using System.Text; +using System.Text.RegularExpressions; +using ChainSafe.Gaming.Web3.Core.Evm; +using Nethereum.ABI.EIP712; +using Nethereum.Signer; +using Nethereum.Util; + +namespace ChainSafe.Gaming.Web3.Core.Debug +{ + public static class HashExtensions + { + public static bool IsSignatureHashValid(this string hash) + { + string regexPattern = @"^0x[a-fA-F0-9]{130}$"; + + return !string.IsNullOrEmpty(hash) && Regex.IsMatch(hash, regexPattern); + } + + public static bool IsSignatureValid(this string hash, string message, string account) + { + return IsSignatureHashValid(hash) && IsSignatureAuthentic(hash, message, account); + } + + public static bool IsTypedDataSignatureValid(this string hash, SerializableTypedData typedData, string account) + { + return IsSignatureHashValid(hash) && IsTypedDataSignatureAuthentic(hash, typedData, account); + } + + public static string AssertSignatureValid(this string hash, string message, string account) + { + if (!IsSignatureValid(hash, message, account)) + { + throw new Web3AssertionException("Signature is not valid."); + } + + return hash; + } + + public static string AssertTypedDataSignatureValid(this string hash, SerializableTypedData typedData, string account) + { + if (!IsTypedDataSignatureValid(hash, typedData, account)) + { + throw new Web3AssertionException("Typed Data Signature is not valid."); + } + + return hash; + } + + /// + /// Check if signer account signed the message. + /// + /// Hash of signed message. + /// Signed message. + /// Signer public account. + /// Did signer sign message. + private static bool IsSignatureAuthentic(string hash, string message, string account) + { + if (!AddressExtensions.IsPublicAddress(account)) + { + return false; + } + + string messageToHash = "\x19" + "Ethereum Signed Message:\n" + message.Length + message; + + return IsSignatureBytesAuthentic(Encoding.UTF8.GetBytes(messageToHash), hash, account); + } + + private static bool IsTypedDataSignatureAuthentic(string hash, SerializableTypedData typedData, string account) + { + if (!AddressExtensions.IsPublicAddress(account)) + { + return false; + } + + var rawTypedData = new TypedDataRaw + { + Types = typedData.Types, + PrimaryType = typedData.PrimaryType, + Message = MemberValueFactory.CreateFromMessage(typedData.Message), + DomainRawValues = MemberValueFactory.CreateFromMessage(typedData.Domain), + }; + + return IsSignatureBytesAuthentic(Eip712TypedDataEncoder.Current.EncodeTypedDataRaw(rawTypedData), hash, account); + } + + private static bool IsSignatureBytesAuthentic(byte[] bytes, string hash, string account) + { + EthECDSASignature signature = MessageSigner.ExtractEcdsaSignature(hash); + + byte[] messageHash = new Sha3Keccack().CalculateHash(bytes); + + var key = EthECKey.RecoverFromSignature(signature, messageHash); + + return key.GetPublicAddress().ToLower().Trim() == account.ToLower().Trim(); + } + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletConfig.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletProviderConfig.cs similarity index 80% rename from src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletConfig.cs rename to src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletProviderConfig.cs index 24f231c3f..d5c17baad 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletConfig.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletProviderConfig.cs @@ -1,6 +1,6 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet { - public interface IWalletConfig + public interface IWalletProviderConfig { public string SignMessageRpcMethodName { get; } diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs index a08ec294d..1b08ff2f5 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs @@ -1,5 +1,6 @@ using ChainSafe.Gaming.Evm.Signers; using ChainSafe.Gaming.Web3.Build; +using ChainSafe.Gaming.Web3.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -7,24 +8,23 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet { public static class WalletProviderExtensions { - internal static IWeb3ServiceCollection UseWalletProvider(this IWeb3ServiceCollection collection, IWalletConfig config) + public static IWeb3ServiceCollection UseWalletProvider(this IWeb3ServiceCollection collection, IWalletProviderConfig config) where TProvider : WalletProvider { collection.AssertServiceNotBound(); collection.AddSingleton(); - collection.Replace(ServiceDescriptor.Singleton(typeof(IWalletConfig), config)); + collection.Replace(ServiceDescriptor.Singleton(typeof(IWalletProviderConfig), config)); return collection; } - internal static IWeb3ServiceCollection UseWalletSigner(this IWeb3ServiceCollection collection) - where TSigner : WalletSigner + public static IWeb3ServiceCollection UseWalletSigner(this IWeb3ServiceCollection collection) { collection.AssertServiceNotBound(); - collection.AddSingleton(); + collection.AddSingleton(); return collection; } diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs index 45969288e..1fae87bed 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using ChainSafe.Gaming.Evm.Signers; using ChainSafe.Gaming.Web3.Core; +using ChainSafe.Gaming.Web3.Core.Debug; using ChainSafe.Gaming.Web3.Core.Evm; namespace ChainSafe.Gaming.Web3.Evm.Wallet @@ -8,9 +9,9 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet public class WalletSigner : ISigner, ILifecycleParticipant { private readonly IWalletProvider walletProvider; - private readonly IWalletConfig walletConfig; + private readonly IWalletProviderConfig walletConfig; - public WalletSigner(IWalletProvider walletProvider, IWalletConfig walletConfig) + public WalletSigner(IWalletProvider walletProvider, IWalletProviderConfig walletConfig) { this.walletProvider = walletProvider; this.walletConfig = walletConfig; @@ -20,20 +21,25 @@ public WalletSigner(IWalletProvider walletProvider, IWalletConfig walletConfig) public virtual async ValueTask WillStartAsync() { - PublicAddress = await walletProvider.Connect(); + string address = await walletProvider.Connect(); + + PublicAddress = address.AssertIsPublicAddress(); } - public virtual Task SignMessage(string message) + public virtual async Task SignMessage(string message) { - return walletProvider.Perform(walletConfig.SignMessageRpcMethodName, message, PublicAddress); + string hash = await walletProvider.Perform(walletConfig.SignMessageRpcMethodName, message, PublicAddress); + + return hash.AssertSignatureValid(message, PublicAddress); } - public virtual Task SignTypedData(SerializableDomain domain, TStructType message) + public virtual async Task SignTypedData(SerializableDomain domain, TStructType message) { SerializableTypedData typedData = new SerializableTypedData(domain, message); - // MetaMask doesn't work with regular eth_signTypedData method, has to be eth_signTypedData_v4. - return walletProvider.Perform(walletConfig.SignTypedMessageRpcMethodName, typedData, PublicAddress); + string hash = await walletProvider.Perform(walletConfig.SignTypedMessageRpcMethodName, typedData, PublicAddress); + + return hash.AssertTypedDataSignatureValid(typedData, PublicAddress); } public virtual async ValueTask WillStopAsync() diff --git a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs index c6230a0c0..bc37c93d4 100644 --- a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs +++ b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs @@ -26,7 +26,7 @@ public Web3Builder ConfigureServices(Web3Builder web3Builder) { return web3Builder.Configure(services => { - services.UseHyperPlay().UseHyperPlaySigner().UseHyperPlayTransactionExecutor(); + services.UseHyperPlay().UseHyperPlayTransactionExecutor(); }); } From 130ed41ef8f2c3429c9040fc1b8d0ed9dbb8e495 Mon Sep 17 00:00:00 2001 From: rob1997 Date: Wed, 29 May 2024 13:35:37 +0300 Subject: [PATCH 03/10] added logout handler for WalletSigner to disconnect --- .../Web3/Evm/Wallet/WalletProviderExtensions.cs | 3 ++- src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs index 1b08ff2f5..01e69e72f 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs @@ -1,6 +1,7 @@ using ChainSafe.Gaming.Evm.Signers; using ChainSafe.Gaming.Web3.Build; using ChainSafe.Gaming.Web3.Core; +using ChainSafe.Gaming.Web3.Core.Logout; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -24,7 +25,7 @@ public static IWeb3ServiceCollection UseWalletSigner(this IWeb3ServiceCollection { collection.AssertServiceNotBound(); - collection.AddSingleton(); + collection.AddSingleton(); return collection; } diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs index 1fae87bed..7220be818 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs @@ -3,10 +3,11 @@ using ChainSafe.Gaming.Web3.Core; using ChainSafe.Gaming.Web3.Core.Debug; using ChainSafe.Gaming.Web3.Core.Evm; +using ChainSafe.Gaming.Web3.Core.Logout; namespace ChainSafe.Gaming.Web3.Evm.Wallet { - public class WalletSigner : ISigner, ILifecycleParticipant + public class WalletSigner : ISigner, ILifecycleParticipant, ILogoutHandler { private readonly IWalletProvider walletProvider; private readonly IWalletProviderConfig walletConfig; @@ -42,7 +43,12 @@ public virtual async Task SignTypedData(SerializableDomain return hash.AssertTypedDataSignatureValid(typedData, PublicAddress); } - public virtual async ValueTask WillStopAsync() + public virtual ValueTask WillStopAsync() + { + return new ValueTask(Task.CompletedTask); + } + + public async Task OnLogout() { await walletProvider.Disconnect(); } From fc19c8df0af4202c968a726b969771eac0c36189 Mon Sep 17 00:00:00 2001 From: rob1997 Date: Mon, 3 Jun 2024 16:15:18 +0300 Subject: [PATCH 04/10] checkpoint --- .../WalletConnect/WalletConnectConfigSO.cs | 3 + .../Tests/Runtime/SampleTestsBase.cs | 4 +- scripts/data/published_dependencies.txt | 2 +- .../HyperPlayExtensions.cs | 16 +--- .../HyperPlayTransactionExecutor.cs | 69 ---------------- .../ChainSafe.Gaming.MetaMask.csproj | 24 ------ .../MetaMaskExtensions.cs | 44 ---------- .../MetaMaskSigner.cs | 73 ----------------- .../MetaMaskTransactionExecutor.cs | 80 ------------------- .../IWalletConnectConfig.cs | 3 +- .../WalletConnectConfig.cs | 39 --------- .../WalletConnectExtensions.cs | 66 ++------------- .../WalletConnectProvider.cs | 26 +++++- .../WalletConnectSigner.cs | 69 ---------------- .../WalletConnectTransactionExecutor.cs | 63 --------------- .../Web3/Core/Debug/HashExtensions.cs | 17 ++++ .../Web3/Core/Evm/Dto/TransactionRequest.cs | 15 ++++ .../Evm/Wallet/WalletProviderExtensions.cs | 10 +++ .../Web3/Evm/Wallet/WalletSigner.cs | 2 +- .../Evm/Wallet/WalletTransactionExecutor.cs | 48 +++++++++++ .../Scripts/Scenes/HyperPlayLoginProvider.cs | 3 +- .../Scripts/Scenes/MetaMaskLoginProvider.cs | 3 +- .../Scenes/WalletConnectLoginProvider.cs | 4 +- 23 files changed, 134 insertions(+), 549 deletions(-) delete mode 100644 src/ChainSafe.Gaming.HyperPlay/HyperPlayTransactionExecutor.cs delete mode 100644 src/ChainSafe.Gaming.MetaMask/ChainSafe.Gaming.MetaMask.csproj delete mode 100644 src/ChainSafe.Gaming.MetaMask/MetaMaskExtensions.cs delete mode 100644 src/ChainSafe.Gaming.MetaMask/MetaMaskSigner.cs delete mode 100644 src/ChainSafe.Gaming.MetaMask/MetaMaskTransactionExecutor.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs delete mode 100644 src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs create mode 100644 src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs index 870024ee9..25552c641 100644 --- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs +++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/WalletConnect/WalletConnectConfigSO.cs @@ -10,6 +10,9 @@ namespace ChainSafe.Gaming.WalletConnect [CreateAssetMenu(menuName = "ChainSafe/WalletConnect/WalletConnect Config", fileName = "WalletConnectConfig", order = 0)] public class WalletConnectConfigSO : ScriptableObject, IWalletConnectConfig { + public string SignMessageRpcMethodName => "personal_sign"; + public string SignTypedMessageRpcMethodName => "eth_signTypedData"; + [field: SerializeField] public bool AutoRenewSession { get; set; } = true; [field: SerializeField] public string ProjectName { get; set; } [field: SerializeField] public string ProjectId { get; set; } diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs b/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs index 101235e55..58931dcb5 100644 --- a/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs +++ b/Packages/io.chainsafe.web3-unity/Tests/Runtime/SampleTestsBase.cs @@ -62,8 +62,8 @@ internal static ValueTask BuildTestWeb3(Web3Builder.ConfigureServicesDeleg services.AddSingleton(new StubWalletConnectProviderConfig()); // can be replaced services.AddSingleton(); - services.UseWalletConnectSigner(); - services.UseWalletConnectTransactionExecutor(); + services.UseWalletSigner(); + services.UseWalletTransactionExecutor(); // Add any contracts we would want to use services.ConfigureRegisteredContracts(contracts => diff --git a/scripts/data/published_dependencies.txt b/scripts/data/published_dependencies.txt index b2fdea8e8..0fcbe1983 100644 --- a/scripts/data/published_dependencies.txt +++ b/scripts/data/published_dependencies.txt @@ -1,2 +1,2 @@ -Packages/io.chainsafe.web3-unity/Runtime/Libraries/:ADRaffy.ENSNormalize;Nethereum.Model;BouncyCastle.Crypto;Nethereum.RLP;ChainSafe.Gaming.Debugging;Nethereum.RPC;ChainSafe.Gaming.Gelato;ChainSafe.Gaming.SygmaClient;Nethereum.Signer.EIP712;ChainSafe.Gaming.InProcessSigner;Nethereum.Signer;ChainSafe.Gaming.InProcessTransactionExecutor;Nethereum.Util;ChainSafe.Gaming.Unity.ThirdParty;Nethereum.Web3;ChainSafe.Gaming.Unity;System.Buffers;ChainSafe.Gaming.WalletConnect;System.Memory;ChainSafe.Gaming;System.Numerics.Vectors;Microsoft.Bcl.AsyncInterfaces;System.Reactive;Microsoft.Extensions.DependencyInjection.Abstractions;System.Runtime.CompilerServices.Unsafe;Microsoft.Extensions.DependencyInjection;System.Runtime.InteropServices.WindowsRuntime;Microsoft.Extensions.Logging.Abstractions;System.Security.Cryptography.Cng;Microsoft.IdentityModel.Abstractions;System.Text.Encodings.Web;Microsoft.IdentityModel.Logging;System.Text.Json;Microsoft.IdentityModel.Tokens;System.Threading.Channels;NBitcoin;System.Threading.Tasks.Extensions;Nethereum.ABI;WalletConnectSharp.Auth;Nethereum.Accounts;WalletConnectSharp.Common;WalletConnectSharp.Events;Nethereum.BlockchainProcessing;WalletConnectSharp.Core;Nethereum.Contracts;WalletConnectSharp.Crypto;Nethereum.Hex;Nethereum.JsonRpc.Client;WalletConnectSharp.Network.Websocket;Nethereum.JsonRpc.IpcClient;WalletConnectSharp.Network;Nethereum.JsonRpc.RpcClient;WalletConnectSharp.Sign;Nethereum.KeyStore;WalletConnectSharp.Storage;Nethereum.Merkle.Patricia;WalletConnectSharp.Web3Wallet;Nethereum.Merkle;Websocket.Client;Nethereum.Metamask;Nethereum.Siwe.Core;Nethereum.Siwe;Nethereum.UI;Nethereum.Unity.Metamask;Nethereum.Unity;ChainSafe.Gaming.MetaMask;ChainSafe.Gaming.MetaMask.Unity;ChainSafe.Gaming.InProcessTransactionExecutor.Unity;ChainSafe.Gaming.Marketplace;ChainSafe.Gaming.HyperPlay +Packages/io.chainsafe.web3-unity/Runtime/Libraries/:ADRaffy.ENSNormalize;Nethereum.Model;BouncyCastle.Crypto;Nethereum.RLP;ChainSafe.Gaming.Debugging;Nethereum.RPC;ChainSafe.Gaming.Gelato;ChainSafe.Gaming.SygmaClient;Nethereum.Signer.EIP712;ChainSafe.Gaming.InProcessSigner;Nethereum.Signer;ChainSafe.Gaming.InProcessTransactionExecutor;Nethereum.Util;ChainSafe.Gaming.Unity.ThirdParty;Nethereum.Web3;ChainSafe.Gaming.Unity;System.Buffers;ChainSafe.Gaming.WalletConnect;System.Memory;ChainSafe.Gaming;System.Numerics.Vectors;Microsoft.Bcl.AsyncInterfaces;System.Reactive;Microsoft.Extensions.DependencyInjection.Abstractions;System.Runtime.CompilerServices.Unsafe;Microsoft.Extensions.DependencyInjection;System.Runtime.InteropServices.WindowsRuntime;Microsoft.Extensions.Logging.Abstractions;System.Security.Cryptography.Cng;Microsoft.IdentityModel.Abstractions;System.Text.Encodings.Web;Microsoft.IdentityModel.Logging;System.Text.Json;Microsoft.IdentityModel.Tokens;System.Threading.Channels;NBitcoin;System.Threading.Tasks.Extensions;Nethereum.ABI;WalletConnectSharp.Auth;Nethereum.Accounts;WalletConnectSharp.Common;WalletConnectSharp.Events;Nethereum.BlockchainProcessing;WalletConnectSharp.Core;Nethereum.Contracts;WalletConnectSharp.Crypto;Nethereum.Hex;Nethereum.JsonRpc.Client;WalletConnectSharp.Network.Websocket;Nethereum.JsonRpc.IpcClient;WalletConnectSharp.Network;Nethereum.JsonRpc.RpcClient;WalletConnectSharp.Sign;Nethereum.KeyStore;WalletConnectSharp.Storage;Nethereum.Merkle.Patricia;WalletConnectSharp.Web3Wallet;Nethereum.Merkle;Websocket.Client;Nethereum.Metamask;Nethereum.Siwe.Core;Nethereum.Siwe;Nethereum.UI;Nethereum.Unity.Metamask;Nethereum.Unity;ChainSafe.Gaming.MetaMask.Unity;ChainSafe.Gaming.InProcessTransactionExecutor.Unity;ChainSafe.Gaming.Marketplace;ChainSafe.Gaming.HyperPlay Packages/io.chainsafe.web3-unity.lootboxes/Chainlink/Runtime/Libraries/:Chainsafe.Gaming.Chainlink;ChainSafe.Gaming.Lootboxes.Chainlink \ No newline at end of file diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs index b15e0c403..ded2ae2a0 100644 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs @@ -19,21 +19,7 @@ public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection co { config ??= new HyperPlayConfig(); - return collection.UseWalletProvider(config).UseWalletSigner(); - } - - /// - /// Binds implementation of as to Web3 as a service. - /// - /// Service collection to bind implementations to. - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseHyperPlayTransactionExecutor(this IWeb3ServiceCollection collection) - { - collection.AssertServiceNotBound(); - - collection.AddSingleton(); - - return collection; + return collection.UseWalletProvider(config); } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayTransactionExecutor.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayTransactionExecutor.cs deleted file mode 100644 index 621e3c7a1..000000000 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayTransactionExecutor.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using ChainSafe.Gaming.Evm.Providers; -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Evm.Transactions; -using ChainSafe.Gaming.Web3; -using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Evm.Wallet; -using Nethereum.RPC.Eth.DTOs; - -namespace ChainSafe.Gaming.HyperPlay -{ - /// - /// Concrete implementation of via HyperPlay desktop client. - /// - public class HyperPlayTransactionExecutor : ITransactionExecutor - { - private readonly IWalletProvider walletProvider; - private readonly ISigner signer; - - /// - /// Initializes a new instance of the class. - /// - /// HyperPlay provider for making RPC requests. - /// Signer for fetching public address. - public HyperPlayTransactionExecutor(IWalletProvider walletProvider, ISigner signer) - { - this.walletProvider = walletProvider; - this.signer = signer; - } - - /// - /// Send a Transaction via HyperPlay desktop Client. - /// This prompts user to approve a transaction on HyperPlay. - /// - /// Transaction to send. - /// Hash response of a successfully executed transaction. - /// Throws Exception if executing transaction fails. - public async Task SendTransaction(TransactionRequest transaction) - { - if (string.IsNullOrEmpty(transaction.From)) - { - transaction.From = signer.PublicAddress; - } - - TransactionInput transactionInput = new TransactionInput - { - From = transaction.From, - To = transaction.To, - Gas = transaction.GasLimit, - GasPrice = transaction.GasPrice, - Value = transaction.Value, - Data = transaction.Data ?? "0x", - Nonce = transaction.Nonce, - AccessList = transaction.AccessList, - }; - - string hash = await walletProvider.Perform("eth_sendTransaction", transactionInput); - - string hashPattern = @"^0x[a-fA-F0-9]{64}$"; - if (!Regex.IsMatch(hash, hashPattern)) - { - throw new Web3Exception($"incorrect txn response format {hash}"); - } - - return await walletProvider.GetTransaction(hash); - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.MetaMask/ChainSafe.Gaming.MetaMask.csproj b/src/ChainSafe.Gaming.MetaMask/ChainSafe.Gaming.MetaMask.csproj deleted file mode 100644 index d695df281..000000000 --- a/src/ChainSafe.Gaming.MetaMask/ChainSafe.Gaming.MetaMask.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - netstandard2.1 - 9.0 - ChainSafe.Gaming.MetaMask - True - ../../global.ruleset - Debug;Release;Test - AnyCPU - - - - - - - - - - - - - - diff --git a/src/ChainSafe.Gaming.MetaMask/MetaMaskExtensions.cs b/src/ChainSafe.Gaming.MetaMask/MetaMaskExtensions.cs deleted file mode 100644 index 5d4fbb25a..000000000 --- a/src/ChainSafe.Gaming.MetaMask/MetaMaskExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Web3.Build; -using ChainSafe.Gaming.Web3.Core; -using ChainSafe.Gaming.Web3.Core.Evm; -using Microsoft.Extensions.DependencyInjection; - -namespace ChainSafe.Gaming.MetaMask -{ - /// - /// and extension methods. - /// - public static class MetaMaskExtensions - { - /// - /// Binds implementation of as to Web3 as a service. - /// - /// Service collection to bind implementations to. - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseMetaMaskSigner(this IWeb3ServiceCollection collection) - { - collection.AssertServiceNotBound(); - - // wallet - collection.AddSingleton(); - - return collection; - } - - /// - /// Binds implementation of as to Web3 as a service. - /// - /// Service collection to bind implementations to. - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseMetaMaskTransactionExecutor(this IWeb3ServiceCollection collection) - { - collection.AssertServiceNotBound(); - - // wallet - collection.AddSingleton(); - - return collection; - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.MetaMask/MetaMaskSigner.cs b/src/ChainSafe.Gaming.MetaMask/MetaMaskSigner.cs deleted file mode 100644 index 62565eadb..000000000 --- a/src/ChainSafe.Gaming.MetaMask/MetaMaskSigner.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Threading.Tasks; -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Web3.Core; -using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Environment; -using ChainSafe.Gaming.Web3.Evm.Wallet; - -namespace ChainSafe.Gaming.MetaMask -{ - /// - /// Implementation of for Metamask. - /// - public class MetaMaskSigner : ISigner, ILifecycleParticipant - { - private readonly IWalletProvider walletProvider; - - /// - /// Initializes a new instance of the class. - /// - /// Metamask provider that connects to Metamask and makes JsonRPC requests. - public MetaMaskSigner(IWalletProvider walletProvider) - { - this.walletProvider = walletProvider; - } - - public string PublicAddress { get; private set; } - - /// - /// Implementation of . - /// Lifetime event method, called during initialization. - /// - /// async awaitable task. - public async ValueTask WillStartAsync() - { - PublicAddress = await walletProvider.Connect(); - } - - /// - /// Implementation of . - /// Sign message using MetaMask. - /// This prompts user to sign a message on MetaMask. - /// - /// Message to sign. - /// Hash response of a successfully signed message. - public Task SignMessage(string message) - { - return walletProvider.Perform("personal_sign", message, PublicAddress); - } - - /// - /// Implementation of . - /// Sign Typed Data using MetaMask. - /// - /// A serializable domain separator. - /// Data to be signed. - /// Data type of data to be signed. - /// Hash response of a successfully signed typed data. - public Task SignTypedData(SerializableDomain domain, TStructType message) - { - SerializableTypedData typedData = new SerializableTypedData(domain, message); - - // MetaMask doesn't work with regular eth_signTypedData method, has to be eth_signTypedData_v4. - return walletProvider.Perform("eth_signTypedData_v4", typedData, PublicAddress); - } - - /// - /// Implementation of . - /// Lifetime event method, called during "Web3.TerminateAsync". - /// - /// async awaitable task. - public ValueTask WillStopAsync() => new(Task.CompletedTask); - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.MetaMask/MetaMaskTransactionExecutor.cs b/src/ChainSafe.Gaming.MetaMask/MetaMaskTransactionExecutor.cs deleted file mode 100644 index ec3ed050d..000000000 --- a/src/ChainSafe.Gaming.MetaMask/MetaMaskTransactionExecutor.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using ChainSafe.Gaming.Evm.Providers; -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Evm.Transactions; -using ChainSafe.Gaming.Web3; -using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Environment; -using ChainSafe.Gaming.Web3.Evm.Wallet; -using Nethereum.RPC.Eth.DTOs; - -namespace ChainSafe.Gaming.MetaMask -{ - /// - /// Implementation of for Metamask. - /// - public class MetaMaskTransactionExecutor : ITransactionExecutor - { - private readonly ILogWriter logWriter; - - private readonly IWalletProvider walletProvider; - - private readonly ISigner signer; - - /// - /// Initializes a new instance of the class. - /// - /// Log Writer used for logging messages and errors. - /// Metamask provider that connects to Metamask and makes JsonRPC requests. - /// Signer for fetching address. - public MetaMaskTransactionExecutor(ILogWriter logWriter, IWalletProvider walletProvider, ISigner signer) - { - this.logWriter = logWriter; - - this.walletProvider = walletProvider; - - this.signer = signer; - } - - /// - /// Implementation of . - /// Send a transaction using Metamask. - /// This prompts user to approve a transaction on Metamask. - /// - /// Transaction to send. - /// Hash response of a successfully executed transaction. - /// Throws Exception if executing transaction fails. - public async Task SendTransaction(TransactionRequest transaction) - { - if (string.IsNullOrEmpty(transaction.From)) - { - transaction.From = signer.PublicAddress; - } - - TransactionInput transactionInput = new TransactionInput - { - From = transaction.From, - To = transaction.To, - Gas = transaction.GasLimit, - GasPrice = transaction.GasPrice, - Value = transaction.Value, - Data = transaction.Data ?? "0x", - Nonce = transaction.Nonce, - AccessList = transaction.AccessList, - }; - - string hash = await walletProvider.Perform("eth_sendTransaction", transactionInput); - - string hashPattern = @"^0x[a-fA-F0-9]{64}$"; - if (!Regex.IsMatch(hash, hashPattern)) - { - throw new Web3Exception($"incorrect txn response format {hash}"); - } - - logWriter.Log($"Transaction executed with hash {hash}"); - - return await walletProvider.GetTransaction(hash); - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs b/src/ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs index 34a16a543..c57d92dd5 100644 --- a/src/ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs +++ b/src/ChainSafe.Gaming.WalletConnect/IWalletConnectConfig.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections.Generic; using ChainSafe.Gaming.WalletConnect.Connection; +using ChainSafe.Gaming.Web3.Evm.Wallet; using WalletConnectSharp.Core; using WalletConnectSharp.Network.Interfaces; @@ -9,7 +10,7 @@ namespace ChainSafe.Gaming.WalletConnect /// /// Interface for WalletConnect configuration. /// - public interface IWalletConnectConfig + public interface IWalletConnectConfig : IWalletProviderConfig { /// /// Set to true if you want to store this session on a disk for the next time. diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs deleted file mode 100644 index 2cd951a17..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs +++ /dev/null @@ -1,39 +0,0 @@ -#nullable enable -using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Connection; -using WalletConnectSharp.Core; -using WalletConnectSharp.Network.Interfaces; - -namespace ChainSafe.Gaming.WalletConnect -{ - public class WalletConnectConfig : IWalletConnectConfig - { - public bool RememberSession { get; set; } - - public bool ForceNewSession { get; set; } - - public bool AutoRenewSession { get; set; } = true; - - public string ProjectName { get; set; } - - public string ProjectId { get; set; } - - public string BaseContext { get; set; } - - public IConnectionBuilder ConnectionBuilder { get; set; } - - public Metadata Metadata { get; set; } - - public string StoragePath { get; set; } - - public IList? EnabledWallets { get; set; } // todo note in comments that some supported wallets are wierd and it's better to decide on which wallets you want to use or don't want to use - - public IList? DisabledWallets { get; set; } - - public WalletLocationOption WalletLocationOption { get; set; } - - public IConnectionHandlerProvider ConnectionHandlerProvider { get; set; } - - public string? OverrideRegistryUri { get; set; } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs index ea5b9c93f..fa1a83d36 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectExtensions.cs @@ -15,28 +15,16 @@ namespace ChainSafe.Gaming.WalletConnect { public static class WalletConnectExtensions { - /// - /// Use this to configure WalletConnect functionality for this instance of . - /// - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection ConfigureWalletConnect(this IWeb3ServiceCollection services, IWalletConnectConfig config) - { - services.Replace(ServiceDescriptor.Singleton(typeof(IWalletConnectConfig), config)); - return services; - } - /// /// Use this to enable WalletConnect functionality for this instance of Web3. /// /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseWalletConnect(this IWeb3ServiceCollection services) + private static IWeb3ServiceCollection UseWalletConnect(this IWeb3ServiceCollection services) { - services.AssertServiceNotBound(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); return services; } @@ -47,41 +35,11 @@ public static IWeb3ServiceCollection UseWalletConnect(this IWeb3ServiceCollectio /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseWalletConnect(this IWeb3ServiceCollection services, IWalletConnectConfig config) { - services.AssertServiceNotBound(); - - services.ConfigureWalletConnect(config); - services.UseWalletConnect(); - - return services; - } - - /// - /// Use this to set as the for this instance of Web3. - /// - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseWalletConnectSigner(this IWeb3ServiceCollection services) - { - EnsureProviderBoundFirst(services); - services.AssertServiceNotBound(); + services = UseWalletConnect(services); - services.AddSingleton(); - - return services; - } - - /// - /// Use this to set as the - /// for this instance of Web3. - /// - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseWalletConnectTransactionExecutor(this IWeb3ServiceCollection services) - { - EnsureProviderBoundFirst(services); - services.AssertServiceNotBound(); - - services.AddSingleton(); + services.Replace(ServiceDescriptor.Singleton(typeof(IWalletConnectConfig), config)); - return services; + return services.UseWalletProvider(config); } /// @@ -119,19 +77,5 @@ public static IConnectionHelper ConnectionHelper(this WalletConnectSubCategory w { return ((IWeb3SubCategory)walletConnect).Web3.ServiceProvider.GetRequiredService(); } - - /// - /// We need this to be sure - /// initializes first as a . - /// - private static void EnsureProviderBoundFirst(IWeb3ServiceCollection services) - { - if (services.Any(descriptor => descriptor.ServiceType == typeof(IWalletProvider))) - { - return; - } - - throw new Web3BuildException($"You should bind {nameof(IWalletProvider)} first."); - } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs index 121dc4174..e6d3c3cef 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectProvider.cs @@ -29,7 +29,7 @@ namespace ChainSafe.Gaming.WalletConnect { /// - /// Default implementation of . + /// Default implementation of . /// public class WalletConnectProvider : WalletProvider, ILifecycleParticipant, IConnectionHelper { @@ -48,6 +48,7 @@ public class WalletConnectProvider : WalletProvider, ILifecycleParticipant, ICon private LocalData localData; private SessionStruct session; private bool connected; + private bool initialized; private IAnalyticsClient analyticsClient; private ConnectionHandlerConfig connectionHandlerConfig; @@ -81,8 +82,18 @@ public WalletConnectProvider( private static bool SessionExpired(SessionStruct s) => s.Expiry != null && Clock.IsExpired((long)s.Expiry); - async ValueTask ILifecycleParticipant.WillStartAsync() + public async ValueTask WillStartAsync() { + await Initialize(); + } + + private async Task Initialize() + { + if (initialized) + { + return; + } + analyticsClient.CaptureEvent(new AnalyticsEvent() { ProjectId = analyticsClient.ProjectConfig.ProjectId, @@ -143,6 +154,8 @@ async ValueTask ILifecycleParticipant.WillStartAsync() } }, }; + + initialized = true; } private void ValidateConfig() @@ -158,10 +171,12 @@ private void ValidateConfig() } } - async ValueTask ILifecycleParticipant.WillStopAsync() + public ValueTask WillStopAsync() { signClient?.Dispose(); core?.Dispose(); + + return new ValueTask(Task.CompletedTask); } public override async Task Connect() @@ -172,6 +187,11 @@ public override async Task Connect() $"Tried connecting {nameof(WalletConnectProvider)}, but it's already been connected."); } + if (!initialized) + { + await Initialize(); + } + try { var sessionStored = !string.IsNullOrEmpty(localData.SessionTopic); diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs deleted file mode 100644 index 06c8d79c0..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Threading.Tasks; -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Web3; -using ChainSafe.Gaming.Web3.Core; -using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Core.Logout; -using ChainSafe.Gaming.Web3.Evm.Wallet; -using WalletConnectSharp.Common.Logging; - -namespace ChainSafe.Gaming.WalletConnect -{ - /// - /// WalletConnect implementation of . - /// - public class WalletConnectSigner : ISigner, ILifecycleParticipant, ILogoutHandler - { - private readonly IWalletProvider provider; - - public WalletConnectSigner(IWalletProvider provider) - { - this.provider = provider; - } - - public string PublicAddress { get; private set; } - - public async ValueTask WillStartAsync() - { - PublicAddress = await provider.Connect(); - } - - ValueTask ILifecycleParticipant.WillStopAsync() => new(Task.CompletedTask); - - public Task OnLogout() => provider.Disconnect(); - - public async Task SignMessage(string message) - { - var hash = await provider.Perform("personal_sign", message, PublicAddress); - - if (!ValidateSignResponse(hash)) - { - throw new Web3Exception("Incorrect response format from signing."); - } - - WCLogger.Log("Successfully signed message."); - return hash; - } - - public async Task SignTypedData(SerializableDomain domain, TStructType message) - { - SerializableTypedData typedData = new SerializableTypedData(domain, message); - - var hash = await provider.Perform("eth_signTypedData", PublicAddress, typedData); - - if (!ValidateSignResponse(hash)) - { - throw new Web3Exception("Incorrect response format from signing."); - } - - WCLogger.Log("Successfully signed typed data."); - return hash; - } - - private static bool ValidateSignResponse(string response) - { - // TODO: validate with regex - return response.StartsWith("0x") && response.Length == 132; - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs deleted file mode 100644 index 6ccb4d53f..000000000 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using ChainSafe.Gaming.Evm.Providers; -using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Evm.Transactions; -using ChainSafe.Gaming.WalletConnect.Models; -using ChainSafe.Gaming.Web3; -using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Evm.Wallet; -using WalletConnectSharp.Common.Logging; - -namespace ChainSafe.Gaming.WalletConnect -{ - /// - /// WalletConnect implementation of . - /// - public class WalletConnectTransactionExecutor : ITransactionExecutor - { - private readonly IWalletProvider provider; - private readonly ISigner signer; - - public WalletConnectTransactionExecutor(IWalletProvider provider, ISigner signer) - { - this.provider = provider; - this.signer = signer; - } - - public async Task SendTransaction(TransactionRequest transaction) - { - if (string.IsNullOrEmpty(transaction.From)) - { - transaction.From = signer.PublicAddress; - } - - var requestData = new TransactionModel - { - From = transaction.From, - To = transaction.To, - Gas = transaction.GasLimit?.HexValue, - GasPrice = transaction.GasPrice?.HexValue, - Value = transaction.Value?.HexValue, - Data = transaction.Data ?? "0x", - Nonce = transaction.Nonce?.HexValue, - }; - - var hash = await provider.Perform("eth_sendTransaction", requestData); - if (!ValidateResponseHash(hash)) - { - throw new Web3Exception($"Incorrect transaction response format: \"{hash}\"."); - } - - WCLogger.Log($"Transaction executed successfully. Hash: {hash}."); - - return await provider.GetTransaction(hash); - - bool ValidateResponseHash(string hash) - { - string hashPattern = @"^0x[a-fA-F0-9]{64}$"; - return Regex.IsMatch(hash, hashPattern); - } - } - } -} \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs b/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs index a7cd15205..b50b19c1e 100644 --- a/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs +++ b/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs @@ -9,6 +9,13 @@ namespace ChainSafe.Gaming.Web3.Core.Debug { public static class HashExtensions { + public static bool IsTransactionHashValid(this string hash) + { + string regexPattern = @"^0x[a-fA-F0-9]{64}$"; + + return !string.IsNullOrEmpty(hash) && Regex.IsMatch(hash, regexPattern); + } + public static bool IsSignatureHashValid(this string hash) { string regexPattern = @"^0x[a-fA-F0-9]{130}$"; @@ -26,6 +33,16 @@ public static bool IsTypedDataSignatureValid(this string hash, Seriali return IsSignatureHashValid(hash) && IsTypedDataSignatureAuthentic(hash, typedData, account); } + public static string AssertTransactionValid(this string hash) + { + if (!IsTransactionHashValid(hash)) + { + throw new Web3AssertionException("Transaction hash is not valid."); + } + + return hash; + } + public static string AssertSignatureValid(this string hash, string message, string account) { if (!IsSignatureValid(hash, message, account)) diff --git a/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs b/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs index 996ea4143..0445c24eb 100644 --- a/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs +++ b/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs @@ -85,6 +85,21 @@ public object Clone() return this.MemberwiseClone(); } + public TransactionInput ToTransactionInput() + { + return new TransactionInput + { + From = From, + To = To, + Gas = GasLimit, + GasPrice = GasPrice, + Value = Value, + Data = Data ?? "0x", + Nonce = Nonce, + AccessList = AccessList, + }; + } + public Dictionary ToRPCParam() { var param = new Dictionary(); diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs index 01e69e72f..028dfb680 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs @@ -1,6 +1,7 @@ using ChainSafe.Gaming.Evm.Signers; using ChainSafe.Gaming.Web3.Build; using ChainSafe.Gaming.Web3.Core; +using ChainSafe.Gaming.Web3.Core.Evm; using ChainSafe.Gaming.Web3.Core.Logout; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -29,5 +30,14 @@ public static IWeb3ServiceCollection UseWalletSigner(this IWeb3ServiceCollection return collection; } + + public static IWeb3ServiceCollection UseWalletTransactionExecutor(this IWeb3ServiceCollection collection) + { + collection.AssertServiceNotBound(); + + collection.AddSingleton(); + + return collection; + } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs index 7220be818..c12d0a8d1 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs @@ -38,7 +38,7 @@ public virtual async Task SignTypedData(SerializableDomain { SerializableTypedData typedData = new SerializableTypedData(domain, message); - string hash = await walletProvider.Perform(walletConfig.SignTypedMessageRpcMethodName, typedData, PublicAddress); + string hash = await walletProvider.Perform(walletConfig.SignTypedMessageRpcMethodName, PublicAddress, typedData); return hash.AssertTypedDataSignatureValid(typedData, PublicAddress); } diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs new file mode 100644 index 000000000..e7dbf9d1e --- /dev/null +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs @@ -0,0 +1,48 @@ +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using ChainSafe.Gaming.Evm.Providers; +using ChainSafe.Gaming.Evm.Signers; +using ChainSafe.Gaming.Evm.Transactions; +using ChainSafe.Gaming.Web3.Core.Debug; +using ChainSafe.Gaming.Web3.Core.Evm; +using ChainSafe.Gaming.Web3.Environment; +using Nethereum.RPC.Eth.DTOs; + +namespace ChainSafe.Gaming.Web3.Evm.Wallet +{ + public class WalletTransactionExecutor : ITransactionExecutor + { + private readonly ILogWriter logWriter; + + private readonly IWalletProvider walletProvider; + + private readonly ISigner signer; + + public WalletTransactionExecutor(ILogWriter logWriter, IWalletProvider walletProvider, ISigner signer) + { + this.logWriter = logWriter; + + this.walletProvider = walletProvider; + + this.signer = signer; + } + + public async Task SendTransaction(TransactionRequest transaction) + { + if (string.IsNullOrEmpty(transaction.From)) + { + transaction.From = signer.PublicAddress; + } + + TransactionInput transactionInput = transaction.ToTransactionInput(); + + string hash = await walletProvider.Perform("eth_sendTransaction", transactionInput); + + hash = hash.AssertTransactionValid(); + + logWriter.Log($"Transaction executed with hash {hash}"); + + return await walletProvider.GetTransaction(hash); + } + } +} \ No newline at end of file diff --git a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs index bc37c93d4..b502bd097 100644 --- a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs +++ b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/HyperPlayLoginProvider.cs @@ -4,6 +4,7 @@ using ChainSafe.Gaming.UnityPackage.Common; using ChainSafe.Gaming.WalletConnect; using ChainSafe.Gaming.Web3.Build; +using ChainSafe.Gaming.Web3.Evm.Wallet; using Scenes; using UnityEngine; using UnityEngine.UI; @@ -26,7 +27,7 @@ public Web3Builder ConfigureServices(Web3Builder web3Builder) { return web3Builder.Configure(services => { - services.UseHyperPlay().UseHyperPlayTransactionExecutor(); + services.UseHyperPlay().UseWalletSigner().UseWalletTransactionExecutor(); }); } diff --git a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/MetaMaskLoginProvider.cs b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/MetaMaskLoginProvider.cs index 11fb3938f..21c2dc125 100644 --- a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/MetaMaskLoginProvider.cs +++ b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/MetaMaskLoginProvider.cs @@ -3,6 +3,7 @@ #if UNITY_WEBGL && !UNITY_EDITOR using ChainSafe.Gaming.MetaMask; using ChainSafe.Gaming.MetaMask.Unity; +using ChainSafe.Gaming.Web3.Evm.Wallet; #endif using ChainSafe.Gaming.Web3.Build; using Scenes; @@ -36,7 +37,7 @@ public Web3Builder ConfigureServices(Web3Builder web3Builder) // Currently Metamask browser connections can only run in WebGL builds. // See point 5 in https://github.com/Nethereum/Unity3dSampleTemplate?tab=readme-ov-file#important-notes. #if UNITY_WEBGL && !UNITY_EDITOR - services.UseMetaMask().UseMetaMaskSigner().UseMetaMaskTransactionExecutor(); + services.UseMetaMask().UseWalletSigner().UseWalletTransactionExecutor(); #else Debug.LogError("Metamask browser connection, currently, only works on WebGL Builds (not in editor)."); #endif diff --git a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/WalletConnectLoginProvider.cs b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/WalletConnectLoginProvider.cs index 21d7dd2ec..8c7673cd3 100644 --- a/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/WalletConnectLoginProvider.cs +++ b/src/UnitySampleProject/Assets/Samples/web3.unity SDK/2.5.0/Web3.Unity Samples/Scripts/Scenes/WalletConnectLoginProvider.cs @@ -1,6 +1,7 @@ using ChainSafe.Gaming.UnityPackage.Common; using ChainSafe.Gaming.WalletConnect; using ChainSafe.Gaming.Web3.Build; +using ChainSafe.Gaming.Web3.Evm.Wallet; using Scenes; using UnityEngine; using UnityEngine.UI; @@ -43,8 +44,7 @@ public Web3Builder ConfigureServices(Web3Builder web3Builder) var rememberSession = rememberSessionToggle.isOn || storedSessionAvailable; services.UseWalletConnect(walletConnectConfig.WithRememberSession(rememberSession)) - .UseWalletConnectSigner() - .UseWalletConnectTransactionExecutor(); + .UseWalletSigner().UseWalletTransactionExecutor(); }); } From 949b13dd071ef39a59ffa22c3b7ee75cbb1c2191 Mon Sep 17 00:00:00 2001 From: rob1997 Date: Wed, 5 Jun 2024 13:57:50 +0300 Subject: [PATCH 05/10] merge fixes --- .../HyperPlayConfig.cs | 4 +++ .../HyperPlayExtensions.cs | 34 +------------------ .../IHyperPlayConfig.cs | 4 ++- 3 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs index eaf0ebd34..df3d9e2cb 100644 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs @@ -5,6 +5,10 @@ namespace ChainSafe.Gaming.HyperPlay /// public class HyperPlayConfig : IHyperPlayConfig { + public string SignMessageRpcMethodName => "personal_sign"; + + public string SignTypedMessageRpcMethodName => "eth_signTypedData_v4"; + /// /// Remember the HyperPlay session. /// Like remember me for login. diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs index f418b75a6..e89f4c8ad 100644 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs @@ -20,41 +20,9 @@ public static class HyperPlayExtensions /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection collection, IHyperPlayConfig config) { - collection.AssertServiceNotBound(); - - collection.AddSingleton(); - collection.AddSingleton(); - collection.Replace(ServiceDescriptor.Singleton(typeof(IHyperPlayConfig), config)); - - return collection; - } - - /// - /// Binds implementation of as to Web3 as a service. - /// - /// Service collection to bind implementations to. - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseHyperPlaySigner(this IWeb3ServiceCollection collection) - { - collection.AssertServiceNotBound(); - - collection.AddSingleton(); - - return collection; - } - - /// - /// Binds implementation of as to Web3 as a service. - /// - /// Service collection to bind implementations to. - /// The same service collection that was passed in. This enables fluent style. - public static IWeb3ServiceCollection UseHyperPlayTransactionExecutor(this IWeb3ServiceCollection collection) - { - collection.AssertServiceNotBound(); - - collection.AddSingleton(); + collection.UseWalletProvider(config); return collection; } diff --git a/src/ChainSafe.Gaming.HyperPlay/IHyperPlayConfig.cs b/src/ChainSafe.Gaming.HyperPlay/IHyperPlayConfig.cs index c1019e971..d2ba52c57 100644 --- a/src/ChainSafe.Gaming.HyperPlay/IHyperPlayConfig.cs +++ b/src/ChainSafe.Gaming.HyperPlay/IHyperPlayConfig.cs @@ -1,9 +1,11 @@ +using ChainSafe.Gaming.Web3.Evm.Wallet; + namespace ChainSafe.Gaming.HyperPlay { /// /// Config for a HyperPlay connection. /// - public interface IHyperPlayConfig + public interface IHyperPlayConfig : IWalletProviderConfig { /// /// Url for connecting to HyperPlay desktop client. From 93dbd6eac1376aeffe9adf62805ca8e11aecba90 Mon Sep 17 00:00:00 2001 From: rob1997 Date: Wed, 5 Jun 2024 15:22:08 +0300 Subject: [PATCH 06/10] compile error fixes --- .../ChainSafe.Gaming.MetaMask.Unity.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ChainSafe.Gaming.MetaMask.Unity/ChainSafe.Gaming.MetaMask.Unity.csproj b/src/ChainSafe.Gaming.MetaMask.Unity/ChainSafe.Gaming.MetaMask.Unity.csproj index 5b6542ee5..6e6a40fc0 100644 --- a/src/ChainSafe.Gaming.MetaMask.Unity/ChainSafe.Gaming.MetaMask.Unity.csproj +++ b/src/ChainSafe.Gaming.MetaMask.Unity/ChainSafe.Gaming.MetaMask.Unity.csproj @@ -11,7 +11,7 @@ - + From 05f76780a68622107397bb6b9beb1cd75f8147ea Mon Sep 17 00:00:00 2001 From: rob1997 Date: Wed, 5 Jun 2024 15:41:25 +0300 Subject: [PATCH 07/10] HyperPlay and MetaMask fixes --- scripts/data/published_dependencies.txt | 2 +- src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs | 2 +- .../HyperPlayExtensions.cs | 6 ++++++ .../MetaMaskConfig.cs | 11 +++++++++++ .../MetaMaskProvider.cs | 14 ++++---------- .../MetaMaskProviderExtensions.cs | 4 +--- .../Scripts/HyperPlayLoginProvider.cs | 3 ++- 7 files changed, 26 insertions(+), 16 deletions(-) create mode 100644 src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs diff --git a/scripts/data/published_dependencies.txt b/scripts/data/published_dependencies.txt index 95a06a814..24e484411 100644 --- a/scripts/data/published_dependencies.txt +++ b/scripts/data/published_dependencies.txt @@ -1,3 +1,3 @@ -Packages/io.chainsafe.web3-unity/Runtime/Libraries/:ADRaffy.ENSNormalize;Nethereum.Model;BouncyCastle.Crypto;Nethereum.RLP;ChainSafe.Gaming.Debugging;Nethereum.RPC;ChainSafe.Gaming.Gelato;ChainSafe.Gaming.SygmaClient;Nethereum.Signer.EIP712;ChainSafe.Gaming.InProcessSigner;Nethereum.Signer;ChainSafe.Gaming.InProcessTransactionExecutor;Nethereum.Util;ChainSafe.Gaming.Unity.ThirdParty;Nethereum.Web3;ChainSafe.Gaming.Unity;System.Buffers;ChainSafe.Gaming.WalletConnect;System.Memory;ChainSafe.Gaming;System.Numerics.Vectors;Microsoft.Bcl.AsyncInterfaces;System.Reactive;Microsoft.Extensions.DependencyInjection.Abstractions;System.Runtime.CompilerServices.Unsafe;Microsoft.Extensions.DependencyInjection;System.Runtime.InteropServices.WindowsRuntime;Microsoft.Extensions.Logging.Abstractions;System.Security.Cryptography.Cng;Microsoft.IdentityModel.Abstractions;System.Text.Encodings.Web;Microsoft.IdentityModel.Logging;System.Text.Json;Microsoft.IdentityModel.Tokens;System.Threading.Channels;NBitcoin;System.Threading.Tasks.Extensions;Nethereum.ABI;WalletConnectSharp.Auth;Nethereum.Accounts;WalletConnectSharp.Common;WalletConnectSharp.Events;Nethereum.BlockchainProcessing;WalletConnectSharp.Core;Nethereum.Contracts;WalletConnectSharp.Crypto;Nethereum.Hex;Nethereum.JsonRpc.Client;WalletConnectSharp.Network.Websocket;Nethereum.JsonRpc.IpcClient;WalletConnectSharp.Network;Nethereum.JsonRpc.RpcClient;WalletConnectSharp.Sign;Nethereum.KeyStore;WalletConnectSharp.Storage;Nethereum.Merkle.Patricia;WalletConnectSharp.Web3Wallet;Nethereum.Merkle;Websocket.Client;Nethereum.Metamask;Nethereum.Siwe.Core;Nethereum.Siwe;Nethereum.UI;Nethereum.Unity.Metamask;Nethereum.Unity;ChainSafe.Gaming.MetaMask;ChainSafe.Gaming.MetaMask.Unity;ChainSafe.Gaming.InProcessTransactionExecutor.Unity;ChainSafe.Gaming.Marketplace +Packages/io.chainsafe.web3-unity/Runtime/Libraries/:ADRaffy.ENSNormalize;Nethereum.Model;BouncyCastle.Crypto;Nethereum.RLP;ChainSafe.Gaming.Debugging;Nethereum.RPC;ChainSafe.Gaming.Gelato;ChainSafe.Gaming.SygmaClient;Nethereum.Signer.EIP712;ChainSafe.Gaming.InProcessSigner;Nethereum.Signer;ChainSafe.Gaming.InProcessTransactionExecutor;Nethereum.Util;ChainSafe.Gaming.Unity.ThirdParty;Nethereum.Web3;ChainSafe.Gaming.Unity;System.Buffers;ChainSafe.Gaming.WalletConnect;System.Memory;ChainSafe.Gaming;System.Numerics.Vectors;Microsoft.Bcl.AsyncInterfaces;System.Reactive;Microsoft.Extensions.DependencyInjection.Abstractions;System.Runtime.CompilerServices.Unsafe;Microsoft.Extensions.DependencyInjection;System.Runtime.InteropServices.WindowsRuntime;Microsoft.Extensions.Logging.Abstractions;System.Security.Cryptography.Cng;Microsoft.IdentityModel.Abstractions;System.Text.Encodings.Web;Microsoft.IdentityModel.Logging;System.Text.Json;Microsoft.IdentityModel.Tokens;System.Threading.Channels;NBitcoin;System.Threading.Tasks.Extensions;Nethereum.ABI;WalletConnectSharp.Auth;Nethereum.Accounts;WalletConnectSharp.Common;WalletConnectSharp.Events;Nethereum.BlockchainProcessing;WalletConnectSharp.Core;Nethereum.Contracts;WalletConnectSharp.Crypto;Nethereum.Hex;Nethereum.JsonRpc.Client;WalletConnectSharp.Network.Websocket;Nethereum.JsonRpc.IpcClient;WalletConnectSharp.Network;Nethereum.JsonRpc.RpcClient;WalletConnectSharp.Sign;Nethereum.KeyStore;WalletConnectSharp.Storage;Nethereum.Merkle.Patricia;WalletConnectSharp.Web3Wallet;Nethereum.Merkle;Websocket.Client;Nethereum.Metamask;Nethereum.Siwe.Core;Nethereum.Siwe;Nethereum.UI;Nethereum.Unity.Metamask;Nethereum.Unity;ChainSafe.Gaming.MetaMask.Unity;ChainSafe.Gaming.InProcessTransactionExecutor.Unity;ChainSafe.Gaming.Marketplace Packages/io.chainsafe.web3-unity.lootboxes/Chainlink/Runtime/Libraries/:Chainsafe.Gaming.Chainlink;ChainSafe.Gaming.Lootboxes.Chainlink Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Libraries/:ChainSafe.Gaming.HyperPlay \ No newline at end of file diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs index df3d9e2cb..c39893da9 100644 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayConfig.cs @@ -7,7 +7,7 @@ public class HyperPlayConfig : IHyperPlayConfig { public string SignMessageRpcMethodName => "personal_sign"; - public string SignTypedMessageRpcMethodName => "eth_signTypedData_v4"; + public string SignTypedMessageRpcMethodName => "eth_signTypedData_v3"; /// /// Remember the HyperPlay session. diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs index e89f4c8ad..f1fde1cb0 100644 --- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs +++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs @@ -20,8 +20,14 @@ public static class HyperPlayExtensions /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection collection, IHyperPlayConfig config) { + collection.AssertServiceNotBound(); + collection.AddSingleton(); + collection.AssertServiceNotBound(); + + collection.Replace(ServiceDescriptor.Singleton(typeof(IHyperPlayConfig), config)); + collection.UseWalletProvider(config); return collection; diff --git a/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs new file mode 100644 index 000000000..8e45715eb --- /dev/null +++ b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs @@ -0,0 +1,11 @@ +using ChainSafe.Gaming.Web3.Evm.Wallet; + +namespace ChainSafe.Gaming.MetaMask.Unity +{ + public class MetaMaskConfig : IWalletProviderConfig + { + public string SignMessageRpcMethodName => "personal_sign"; + + public string SignTypedMessageRpcMethodName => "eth_signTypedData_v4"; + } +} \ No newline at end of file diff --git a/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProvider.cs b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProvider.cs index fbfe64000..f3de37d0e 100644 --- a/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProvider.cs +++ b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProvider.cs @@ -11,9 +11,9 @@ namespace ChainSafe.Gaming.MetaMask.Unity { /// - /// Concrete implementation of . + /// Concrete implementation of . /// - public class MetaMaskProvider : WalletProvider, ILogoutHandler + public class MetaMaskProvider : WalletProvider { private readonly ILogWriter logWriter; @@ -63,7 +63,8 @@ public MetaMaskProvider(ILogWriter logWriter, IAnalyticsClient analyticsClient, public override Task Disconnect() { - // Currently no disconnect logic for MetaMask lib on NEthereum. + Object.Destroy(metaMaskController.gameObject); + return Task.CompletedTask; } @@ -89,12 +90,5 @@ public override async Task Connect() return await metaMaskController.Connect(); } - - public Task OnLogout() - { - Object.Destroy(metaMaskController.gameObject); - - return Task.CompletedTask; - } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProviderExtensions.cs b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProviderExtensions.cs index 1f67696b9..0435a101d 100644 --- a/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProviderExtensions.cs +++ b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskProviderExtensions.cs @@ -17,10 +17,8 @@ public static class MetaMaskProviderExtensions /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseMetaMask(this IWeb3ServiceCollection collection) { - collection.AssertServiceNotBound(); - // wallet - collection.AddSingleton(); + collection.UseWalletProvider(new MetaMaskConfig()); return collection; } diff --git a/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs b/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs index 7ccf6694d..f71ba2bad 100644 --- a/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs +++ b/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs @@ -1,6 +1,7 @@ using ChainSafe.Gaming.HyperPlay; using ChainSafe.Gaming.UnityPackage.Common; using ChainSafe.Gaming.Web3.Build; +using ChainSafe.Gaming.Web3.Evm.Wallet; using Microsoft.Extensions.DependencyInjection; using Scenes; using UnityEngine; @@ -46,7 +47,7 @@ public Web3Builder ConfigureServices(Web3Builder web3Builder) services.UseHyperPlay(new HyperPlayConfig { RememberSession = rememberMeToggle.isOn || _storedSessionAvailable, - }).UseHyperPlaySigner().UseHyperPlayTransactionExecutor(); + }).UseWalletSigner().UseWalletTransactionExecutor(); }); } From aff0627c22e5e8c14523782dab9d7731ee44673f Mon Sep 17 00:00:00 2001 From: rob1997 Date: Thu, 6 Jun 2024 11:56:33 +0300 Subject: [PATCH 08/10] fixed send transaction --- .../Methods/EthSendTransaction.cs | 6 +++--- .../Web3/Core/Evm/Dto/TransactionRequest.cs | 15 --------------- .../Evm/Wallet/WalletTransactionExecutor.cs | 18 ++++-------------- 3 files changed, 7 insertions(+), 32 deletions(-) diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs index 3e2ee0f05..13cabab87 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using ChainSafe.Gaming.WalletConnect.Models; +using ChainSafe.Gaming.Evm.Transactions; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Network.Models; @@ -10,13 +10,13 @@ namespace ChainSafe.Gaming.WalletConnect.Methods /// [RpcMethod("eth_sendTransaction")] [RpcRequestOptions(Clock.ONE_MINUTE, 99999)] - public class EthSendTransaction : List + public class EthSendTransaction : List { /// /// Initializes a new instance of the class. /// /// Transaction to be sent. - public EthSendTransaction(params TransactionModel[] transactions) + public EthSendTransaction(params TransactionRequest[] transactions) : base(transactions) { } diff --git a/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs b/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs index 0445c24eb..996ea4143 100644 --- a/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs +++ b/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs @@ -85,21 +85,6 @@ public object Clone() return this.MemberwiseClone(); } - public TransactionInput ToTransactionInput() - { - return new TransactionInput - { - From = From, - To = To, - Gas = GasLimit, - GasPrice = GasPrice, - Value = Value, - Data = Data ?? "0x", - Nonce = Nonce, - AccessList = AccessList, - }; - } - public Dictionary ToRPCParam() { var param = new Dictionary(); diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs index e7dbf9d1e..6c4ec96ad 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs @@ -12,16 +12,12 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet { public class WalletTransactionExecutor : ITransactionExecutor { - private readonly ILogWriter logWriter; - private readonly IWalletProvider walletProvider; private readonly ISigner signer; - public WalletTransactionExecutor(ILogWriter logWriter, IWalletProvider walletProvider, ISigner signer) + public WalletTransactionExecutor(IWalletProvider walletProvider, ISigner signer) { - this.logWriter = logWriter; - this.walletProvider = walletProvider; this.signer = signer; @@ -29,19 +25,13 @@ public WalletTransactionExecutor(ILogWriter logWriter, IWalletProvider walletPro public async Task SendTransaction(TransactionRequest transaction) { - if (string.IsNullOrEmpty(transaction.From)) - { - transaction.From = signer.PublicAddress; - } + transaction.From ??= signer.PublicAddress; + transaction.Data ??= "0x"; - TransactionInput transactionInput = transaction.ToTransactionInput(); - - string hash = await walletProvider.Perform("eth_sendTransaction", transactionInput); + string hash = await walletProvider.Perform("eth_sendTransaction", transaction); hash = hash.AssertTransactionValid(); - logWriter.Log($"Transaction executed with hash {hash}"); - return await walletProvider.GetTransaction(hash); } } From 9f04aa85c507411e3a69f9e6c8cb12fe93c6fdbd Mon Sep 17 00:00:00 2001 From: rob1997 Date: Mon, 10 Jun 2024 11:36:04 +0300 Subject: [PATCH 09/10] docs added --- .../MetaMaskConfig.cs | 3 ++ .../Web3/Core/Debug/HashExtensions.cs | 48 +++++++++++++++++++ .../Web3/Evm/Wallet/IWalletProviderConfig.cs | 9 ++++ .../Evm/Wallet/WalletProviderExtensions.cs | 17 +++++++ .../Web3/Evm/Wallet/WalletSigner.cs | 4 ++ .../Evm/Wallet/WalletTransactionExecutor.cs | 4 ++ src/UnitySampleProject/Assets/csc.rsp.meta | 7 +++ 7 files changed, 92 insertions(+) create mode 100644 src/UnitySampleProject/Assets/csc.rsp.meta diff --git a/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs index 8e45715eb..d7f921016 100644 --- a/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs +++ b/src/ChainSafe.Gaming.MetaMask.Unity/MetaMaskConfig.cs @@ -2,6 +2,9 @@ namespace ChainSafe.Gaming.MetaMask.Unity { + /// + /// Concrete implementation of for connecting to MetaMask wallet. + /// public class MetaMaskConfig : IWalletProviderConfig { public string SignMessageRpcMethodName => "personal_sign"; diff --git a/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs b/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs index b50b19c1e..82f5a71d8 100644 --- a/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs +++ b/src/ChainSafe.Gaming/Web3/Core/Debug/HashExtensions.cs @@ -9,6 +9,11 @@ namespace ChainSafe.Gaming.Web3.Core.Debug { public static class HashExtensions { + /// + /// Make sure transaction hash is valid. + /// + /// Hash of transaction to be validated. + /// Is Hash Valid. public static bool IsTransactionHashValid(this string hash) { string regexPattern = @"^0x[a-fA-F0-9]{64}$"; @@ -16,6 +21,11 @@ public static bool IsTransactionHashValid(this string hash) return !string.IsNullOrEmpty(hash) && Regex.IsMatch(hash, regexPattern); } + /// + /// Is Signature Hash Valid. + /// + /// Hash of signature to be validated. + /// Is Hash Valid. public static bool IsSignatureHashValid(this string hash) { string regexPattern = @"^0x[a-fA-F0-9]{130}$"; @@ -23,16 +33,37 @@ public static bool IsSignatureHashValid(this string hash) return !string.IsNullOrEmpty(hash) && Regex.IsMatch(hash, regexPattern); } + /// + /// Make sure signature hash is valid and also authentic (signer is account). + /// + /// Signature Hash to be validated. + /// Signed Message. + /// Signer account. + /// Is signature valid. public static bool IsSignatureValid(this string hash, string message, string account) { return IsSignatureHashValid(hash) && IsSignatureAuthentic(hash, message, account); } + /// + /// Make sure typed data signature hash is valid and also authentic (signer is account). + /// + /// Signature has to be validated. + /// Signed typed data. + /// Signer account. + /// Message type to be signed. + /// Is signature valid. public static bool IsTypedDataSignatureValid(this string hash, SerializableTypedData typedData, string account) { return IsSignatureHashValid(hash) && IsTypedDataSignatureAuthentic(hash, typedData, account); } + /// + /// Assert if transaction hash is valid. + /// + /// Transaction hash to be validated. + /// Validated transaction hash. + /// Throws if transaction hash is not valid. public static string AssertTransactionValid(this string hash) { if (!IsTransactionHashValid(hash)) @@ -43,6 +74,14 @@ public static string AssertTransactionValid(this string hash) return hash; } + /// + /// Assert if signature is valid and authentic (signer is account). + /// + /// Signature hash. + /// Signed Message. + /// Signer account. + /// Validated signature hash. + /// Throws if signature isn't valid or authentic. public static string AssertSignatureValid(this string hash, string message, string account) { if (!IsSignatureValid(hash, message, account)) @@ -53,6 +92,15 @@ public static string AssertSignatureValid(this string hash, string message, stri return hash; } + /// + /// Assert if signature is valid and authentic (signer is account). + /// + /// Signature hash. + /// Signed Typed data. + /// Signer account. + /// Type of message. + /// Validated signature hash. + /// Throws if signature isn't valid or authentic. public static string AssertTypedDataSignatureValid(this string hash, SerializableTypedData typedData, string account) { if (!IsTypedDataSignatureValid(hash, typedData, account)) diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletProviderConfig.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletProviderConfig.cs index d5c17baad..e8d1c5867 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletProviderConfig.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/IWalletProviderConfig.cs @@ -1,9 +1,18 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet { + /// + /// Wallet provider config for connecting to a wallet. + /// public interface IWalletProviderConfig { + /// + /// Sign message RPC method name, usually "personal_sign". + /// public string SignMessageRpcMethodName { get; } + /// + /// Sign Typed message RPC method name, usually "eth_signTypedData". + /// public string SignTypedMessageRpcMethodName { get; } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs index 028dfb680..4f5656a97 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletProviderExtensions.cs @@ -10,6 +10,13 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet { public static class WalletProviderExtensions { + /// + /// Inject a Wallet Provider for . + /// + /// Collection of services. + /// Config for wallet connection, injected . + /// Concrete Type of provider to be injected. + /// Collection of services with services injected. public static IWeb3ServiceCollection UseWalletProvider(this IWeb3ServiceCollection collection, IWalletProviderConfig config) where TProvider : WalletProvider { @@ -22,6 +29,11 @@ public static IWeb3ServiceCollection UseWalletProvider(this IWeb3Serv return collection; } + /// + /// Inject for . + /// + /// Collection of registered services. + /// Collection of registered services with a registered . public static IWeb3ServiceCollection UseWalletSigner(this IWeb3ServiceCollection collection) { collection.AssertServiceNotBound(); @@ -31,6 +43,11 @@ public static IWeb3ServiceCollection UseWalletSigner(this IWeb3ServiceCollection return collection; } + /// + /// Inject for . + /// + /// Collection of registered services. + /// Collection of registered services with a registered . public static IWeb3ServiceCollection UseWalletTransactionExecutor(this IWeb3ServiceCollection collection) { collection.AssertServiceNotBound(); diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs index c12d0a8d1..f2b6931e9 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletSigner.cs @@ -7,6 +7,10 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet { + /// + /// Concrete implementation of for signing messages using a wallet. + /// This can be used with any wallet provider that implements . + /// public class WalletSigner : ISigner, ILifecycleParticipant, ILogoutHandler { private readonly IWalletProvider walletProvider; diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs index 6c4ec96ad..27bf47f0a 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs @@ -10,6 +10,10 @@ namespace ChainSafe.Gaming.Web3.Evm.Wallet { + /// + /// Concrete implementation of for sending transactions using a wallet. + /// This can be used with any wallet provider that implements . + /// public class WalletTransactionExecutor : ITransactionExecutor { private readonly IWalletProvider walletProvider; diff --git a/src/UnitySampleProject/Assets/csc.rsp.meta b/src/UnitySampleProject/Assets/csc.rsp.meta new file mode 100644 index 000000000..b7d246f8d --- /dev/null +++ b/src/UnitySampleProject/Assets/csc.rsp.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8630a7b4d41c54991bb6abdad2d1bbe6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From fe6796e2e0b8e627f7330c97c253609462d8bf6c Mon Sep 17 00:00:00 2001 From: rob1997 Date: Tue, 11 Jun 2024 17:29:15 +0300 Subject: [PATCH 10/10] made requested fixes --- .../Methods/EthSendTransaction.cs | 19 +++++++++++++++---- .../Web3/Core/Evm/Dto/TransactionRequest.cs | 15 +++++++++++++++ .../Evm/Wallet/WalletTransactionExecutor.cs | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs index 13cabab87..3b87f2235 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs @@ -1,5 +1,7 @@ +using System; using System.Collections.Generic; -using ChainSafe.Gaming.Evm.Transactions; +using ChainSafe.Gaming.WalletConnect.Models; +using Nethereum.RPC.Eth.DTOs; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Network.Models; @@ -10,14 +12,23 @@ namespace ChainSafe.Gaming.WalletConnect.Methods /// [RpcMethod("eth_sendTransaction")] [RpcRequestOptions(Clock.ONE_MINUTE, 99999)] - public class EthSendTransaction : List + public class EthSendTransaction : List { /// /// Initializes a new instance of the class. /// /// Transaction to be sent. - public EthSendTransaction(params TransactionRequest[] transactions) - : base(transactions) + public EthSendTransaction(params TransactionInput[] transactions) + : base(Array.ConvertAll(transactions, input => new TransactionModel + { + From = input.From, + To = input.To, + Gas = input.Gas?.HexValue, + GasPrice = input.GasPrice?.HexValue, + Value = input.Value?.HexValue, + Data = input.Data, + Nonce = input.Nonce?.HexValue, + })) { } diff --git a/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs b/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs index 996ea4143..82d3f8189 100644 --- a/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs +++ b/src/ChainSafe.Gaming/Web3/Core/Evm/Dto/TransactionRequest.cs @@ -85,6 +85,21 @@ public object Clone() return this.MemberwiseClone(); } + public TransactionInput ToTransactionInput() + { + return new TransactionInput + { + From = From, + To = To, + Gas = GasLimit, + GasPrice = GasPrice, + Value = Value, + Data = Data, + Nonce = Nonce, + AccessList = AccessList, + }; + } + public Dictionary ToRPCParam() { var param = new Dictionary(); diff --git a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs index 27bf47f0a..5974a645c 100644 --- a/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs +++ b/src/ChainSafe.Gaming/Web3/Evm/Wallet/WalletTransactionExecutor.cs @@ -32,7 +32,7 @@ public async Task SendTransaction(TransactionRequest transa transaction.From ??= signer.PublicAddress; transaction.Data ??= "0x"; - string hash = await walletProvider.Perform("eth_sendTransaction", transaction); + string hash = await walletProvider.Perform("eth_sendTransaction", transaction.ToTransactionInput()); hash = hash.AssertTransactionValid();