diff --git a/Packages/io.chainsafe.web3-unity/Tests/Runtime/MiscTests.cs b/Packages/io.chainsafe.web3-unity/Tests/Runtime/MiscTests.cs index 13a019903..749377af0 100644 --- a/Packages/io.chainsafe.web3-unity/Tests/Runtime/MiscTests.cs +++ b/Packages/io.chainsafe.web3-unity/Tests/Runtime/MiscTests.cs @@ -152,7 +152,7 @@ public IEnumerator TestTransactionStatus() [UnityTest] public IEnumerator TestMint721() { - config.TestResponse = "0xa9f953f9845e7d49d778d6fed622d566daf09e8e1c793297c7cab54782e1aae9"; + config.TestResponse = "0xd3027fbfd9d5ddb5ea0ef75f5b128581d9268ad67728d150657f915c8910f9f0"; var mint721 = _sample.Mint721(Mint721Abi, Mint721Address, MintUri); diff --git a/src/ChainSafe.Gaming.InProcessSigner/InProcessSigner.cs b/src/ChainSafe.Gaming.InProcessSigner/InProcessSigner.cs index eff840db2..f3148e18e 100644 --- a/src/ChainSafe.Gaming.InProcessSigner/InProcessSigner.cs +++ b/src/ChainSafe.Gaming.InProcessSigner/InProcessSigner.cs @@ -10,11 +10,19 @@ namespace ChainSafe.Gaming.InProcessSigner { + /// + /// Concrete Implementation of that uses a Private Key to sign messages and typed data. + /// public class InProcessSigner : ISigner { private EthECKey privateKey; private EthereumMessageSigner messageSigner; + /// + /// Initializes a new instance of the class. + /// + /// Injected Config for signer containing a private key. + /// Throws Exception if initializing instance fails. public InProcessSigner(InProcessSignerConfig config) { privateKey = config.PrivateKey ?? @@ -22,11 +30,27 @@ public InProcessSigner(InProcessSignerConfig config) messageSigner = new(); } + /// + /// Implementation of using In Process. + /// + /// Public address of signer. public Task GetAddress() => Task.FromResult(privateKey.GetPublicAddress()); + /// + /// Implementation of using In Process. + /// + /// Message to be signed. + /// Hash response of a successfully signed message. public Task SignMessage(string message) => Task.FromResult(messageSigner.EncodeUTF8AndSign(message, privateKey)); + /// + /// Implementation of using In Process. + /// + /// Serializable domain for signing typed data. + /// Message/Data to be signed. + /// Type of Data to be signed. + /// Hash response of a successfully signed typed data. public Task SignTypedData(SerializableDomain domain, TStructType message) { var primaryType = typeof(TStructType).Name; @@ -45,6 +69,10 @@ public Task SignTypedData(SerializableDomain domain, TStruc return Task.FromResult(Eip712TypedDataSigner.Current.SignTypedDataV4(typedData, privateKey)); } + /// + /// Get private key of . + /// + /// Private key of . public EthECKey GetKey() => privateKey; } } diff --git a/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerConfig.cs b/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerConfig.cs index 59c4c04ee..b17f3e052 100644 --- a/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerConfig.cs +++ b/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerConfig.cs @@ -1,9 +1,16 @@ -using Nethereum.Signer; +using ChainSafe.Gaming.Evm.Signers; +using Nethereum.Signer; namespace ChainSafe.Gaming.InProcessSigner { + /// + /// Config for . + /// public class InProcessSignerConfig { + /// + /// Private key of . + /// public EthECKey? PrivateKey { get; set; } } } diff --git a/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerExtensions.cs b/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerExtensions.cs index a8bdefa9f..a6a412d83 100644 --- a/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerExtensions.cs +++ b/src/ChainSafe.Gaming.InProcessSigner/InProcessSignerExtensions.cs @@ -5,8 +5,17 @@ namespace ChainSafe.Gaming.InProcessSigner { + /// + /// extension methods. + /// public static class InProcessSignerExtensions { + /// + /// Bind as and a to . + /// + /// Service Collection to bind services to. + /// Config used by . + /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseInProcessSigner(this IWeb3ServiceCollection collection, InProcessSignerConfig configuration) { collection.UseInProcessSigner(); @@ -14,6 +23,11 @@ public static IWeb3ServiceCollection UseInProcessSigner(this IWeb3ServiceCollect return collection; } + /// + /// Bind as to . + /// + /// Service Collection to bind services to. + /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseInProcessSigner(this IWeb3ServiceCollection collection) { collection.AssertServiceNotBound(); @@ -21,6 +35,12 @@ public static IWeb3ServiceCollection UseInProcessSigner(this IWeb3ServiceCollect return collection; } + /// + /// Binds a to . + /// + /// Service Collection to bind services to. + /// Config used by . + /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection ConfigureInProcessSigner(this IWeb3ServiceCollection collection, InProcessSignerConfig configuration) { collection.Replace(ServiceDescriptor.Singleton(typeof(InProcessSignerConfig), configuration)); diff --git a/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs b/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs index d3c833c69..067f958ad 100644 --- a/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs +++ b/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutor.cs @@ -13,12 +13,22 @@ namespace ChainSafe.Gaming.InProcessTransactionExecutor { + /// + /// Concrete Implementation of that uses a private key to execute transactions. + /// public class InProcessTransactionExecutor : ITransactionExecutor { private readonly NWeb3 web3; private readonly IRpcProvider rpcProvider; private readonly string accountAddress; + /// + /// Initializes a new instance of the class. + /// + /// Injected . + /// Injected . + /// Injected . + /// Throws exception if initializing instance fails. public InProcessTransactionExecutor(ISigner signer, IChainConfig chainConfig, IRpcProvider rpcProvider) { // It should be possible to set up other signers to work with this as well. @@ -45,6 +55,14 @@ public InProcessTransactionExecutor(ISigner signer, IChainConfig chainConfig, IR this.rpcProvider = rpcProvider; } + /// + /// Implementation of . + /// Send a transaction using Wallet Connect. + /// This prompts user to approve a transaction on a connected wallet. + /// + /// 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)) diff --git a/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutorExtensions.cs b/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutorExtensions.cs index 44f7584e6..143cf19b2 100644 --- a/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutorExtensions.cs +++ b/src/ChainSafe.Gaming.InProcessTransactionExecutor/InProcessTransactionExecutorExtensions.cs @@ -4,8 +4,16 @@ namespace ChainSafe.Gaming.InProcessTransactionExecutor { + /// + /// Extension methods for . + /// public static class InProcessTransactionExecutorExtensions { + /// + /// 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 UseInProcessSigner(this IWeb3ServiceCollection collection) { collection.AssertServiceNotBound(); diff --git a/src/ChainSafe.Gaming.NetCore/ChainConfig.cs b/src/ChainSafe.Gaming.NetCore/ChainConfig.cs index 2f2e5661e..bc4bf2648 100644 --- a/src/ChainSafe.Gaming.NetCore/ChainConfig.cs +++ b/src/ChainSafe.Gaming.NetCore/ChainConfig.cs @@ -2,18 +2,46 @@ namespace ChainSafe.Gaming.NetCore { + /// + /// Concrete Implementation of . + /// Holds all config files related to chain and network. + /// public class ChainConfig : IChainConfig { + /// + /// Implementation of + /// Chain Id, eg. "5" for Goerli. + /// public string ChainId { get; set; } + /// + /// Implementation of + /// Chain, for eg. "Ethereum". + /// public string Chain { get; set; } + /// + /// Implementation of + /// Specific Chain Network, eg. "mainnet" or "goerli". + /// public string Network { get; set; } + /// + /// Implementation of + /// RPC node link. + /// public string Rpc { get; set; } + /// + /// Implementation of + /// IPC link. + /// public string Ipc { get; set; } + /// + /// Implementation of + /// WebSocket link. + /// public string Ws { get; set; } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.NetCore/NetCoreEnvironmentExtensions.cs b/src/ChainSafe.Gaming.NetCore/NetCoreEnvironmentExtensions.cs index 7a3d24cdd..1deb59707 100644 --- a/src/ChainSafe.Gaming.NetCore/NetCoreEnvironmentExtensions.cs +++ b/src/ChainSafe.Gaming.NetCore/NetCoreEnvironmentExtensions.cs @@ -5,8 +5,17 @@ namespace ChainSafe.Gaming.NetCore { + /// + /// NetCore environment extension. + /// Binds implementations to Web3 as a service for NetCore environment. + /// public static class NetCoreEnvironmentExtensions { + /// + /// Binds implementation of , and to Web3 as a service for NetCore environment. + /// + /// Service collection to bind implementations to. + /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseNetCoreEnvironment(this IWeb3ServiceCollection services) { services.UseApiAnalytics(); diff --git a/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs b/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs index 986d43acd..a666b4b5d 100644 --- a/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs +++ b/src/ChainSafe.Gaming.NetCore/NetCoreHttpClient.cs @@ -7,10 +7,16 @@ namespace ChainSafe.Gaming.NetCore { + /// + /// Implementation of for NetCore environment. + /// public class NetCoreHttpClient : IHttpClient { private readonly HttpClient originalClient; + /// + /// Initializes a new instance of the class. + /// public NetCoreHttpClient() { originalClient = new HttpClient(); @@ -28,12 +34,24 @@ private static async ValueTask> ResponseToNetworkRespons } } + /// + /// Get Raw response from http request with a GET method. + /// + /// Url of request to be made. + /// Raw response to the request. public async ValueTask> GetRaw(string url) { var response = await originalClient.GetAsync(url); return await ResponseToNetworkResponse(response); } + /// + /// Get Raw response from http request with a POST method. + /// + /// Url of request to be made. + /// Request data/body. + /// Content type request header. + /// Raw response to the request. public async ValueTask> PostRaw(string url, string data, string contentType) { var requestContent = new StringContent(data, Encoding.UTF8, contentType); @@ -41,12 +59,26 @@ public async ValueTask> PostRaw(string url, string data, return await ResponseToNetworkResponse(response); } + /// + /// Get response as from http request with a GET method. + /// + /// Url of request to be made. + /// Response body model type. + /// Response as a . public async ValueTask> Get(string url) { var response = await GetRaw(url); return response.Map(x => JsonConvert.DeserializeObject(x)); } + /// + /// Get response as from http request with a GET method. + /// + /// Url of request to be made. + /// Request data/body. + /// Request data/body model type. + /// Response data/body type. + /// Response as a . public async ValueTask> Post(string url, TRequest data) { var requestJson = JsonConvert.SerializeObject(data); diff --git a/src/ChainSafe.Gaming.NetCore/NetCoreLogWriter.cs b/src/ChainSafe.Gaming.NetCore/NetCoreLogWriter.cs index 37a11ce09..56ca4cde7 100644 --- a/src/ChainSafe.Gaming.NetCore/NetCoreLogWriter.cs +++ b/src/ChainSafe.Gaming.NetCore/NetCoreLogWriter.cs @@ -3,13 +3,24 @@ namespace ChainSafe.Gaming.NetCore { + /// + /// Implementation of for NetCore environment. + /// public class NetCoreLogWriter : ILogWriter { + /// + /// Log message. + /// + /// Message to be logged. public void Log(string message) { Console.WriteLine(FormatMessage(message, "INFO")); } + /// + /// Log error message. + /// + /// Error message to be logged. public void LogError(string message) { Console.WriteLine(FormatMessage(message, "ERROR")); diff --git a/src/ChainSafe.Gaming.NetCore/NetCoreOperatingSystemMediator.cs b/src/ChainSafe.Gaming.NetCore/NetCoreOperatingSystemMediator.cs index 7c0ee785b..5cd20bc4d 100644 --- a/src/ChainSafe.Gaming.NetCore/NetCoreOperatingSystemMediator.cs +++ b/src/ChainSafe.Gaming.NetCore/NetCoreOperatingSystemMediator.cs @@ -2,12 +2,28 @@ namespace ChainSafe.Gaming.NetCore { + /// + /// Implementation of for NetCore environment. + /// public class NetCoreOperatingSystemMediator : IOperatingSystemMediator { + /// + /// Is platform on Mobile or not. + /// + /// Not Implemented. public bool IsMobilePlatform => throw new System.NotImplementedException(); + /// + /// Current Platform enum. + /// + /// Not Implemented. public Platform Platform => throw new System.NotImplementedException(); + /// + /// Open a Url using Http for .NetCore environment. + /// + /// Url to open. + /// Not Implemented. public void OpenUrl(string url) => throw new System.NotImplementedException(); } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.NetCore/ProjectConfig.cs b/src/ChainSafe.Gaming.NetCore/ProjectConfig.cs index 96753b87d..0b0f0426d 100644 --- a/src/ChainSafe.Gaming.NetCore/ProjectConfig.cs +++ b/src/ChainSafe.Gaming.NetCore/ProjectConfig.cs @@ -2,8 +2,15 @@ namespace ChainSafe.Gaming.NetCore { + /// + /// Implementation of for NetCore environment. + /// public class ProjectConfig : IProjectConfig { + /// + /// Implementation of + /// Project Id fetched from the ChainSafe Gaming web dashboard. + /// public string ProjectId { get; set; } } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/IWalletConnectCustomProvider.cs b/src/ChainSafe.Gaming.WalletConnect/IWalletConnectCustomProvider.cs index 6d1ad4a32..3b55b3f0c 100644 --- a/src/ChainSafe.Gaming.WalletConnect/IWalletConnectCustomProvider.cs +++ b/src/ChainSafe.Gaming.WalletConnect/IWalletConnectCustomProvider.cs @@ -2,12 +2,15 @@ namespace ChainSafe.Gaming.WalletConnect { + /// + /// Connect and disconnect to a wallet via Wallet Connect and make a Json RPC request. + /// public interface IWalletConnectCustomProvider { /// - /// connects using Wallet Connect. + /// Connects using Wallet Connect. /// - /// connect address. + /// Connected address. public Task Connect(); /// @@ -22,7 +25,7 @@ public interface IWalletConnectCustomProvider /// /// Disconnect from a Wallet Connect Session. /// - /// Disconnect Task. + /// Disconnect async Task. public Task Disconnect(); } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs index 25c8fe51f..3e2ee0f05 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSendTransaction.cs @@ -5,15 +5,26 @@ namespace ChainSafe.Gaming.WalletConnect.Methods { + /// + /// Send Transaction Wallet Connect Json RPC method params. + /// [RpcMethod("eth_sendTransaction")] [RpcRequestOptions(Clock.ONE_MINUTE, 99999)] public class EthSendTransaction : List { + /// + /// Initializes a new instance of the class. + /// + /// Transaction to be sent. public EthSendTransaction(params TransactionModel[] transactions) : base(transactions) { } + /// + /// Initializes a new instance of the class used by json.net. + /// Preserved for Unity using ChainSafe.Gaming.Unity/link.xml. + /// public EthSendTransaction() { } diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignMessage.cs b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignMessage.cs index 38d4ebef1..8726ebbfd 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignMessage.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignMessage.cs @@ -4,15 +4,27 @@ namespace ChainSafe.Gaming.WalletConnect.Methods { + /// + /// Sign message Wallet Connect Json RPC method params. + /// [RpcMethod("personal_sign")] [RpcRequestOptions(Clock.ONE_MINUTE, 99997)] public class EthSignMessage : List { + /// + /// Initializes a new instance of the class. + /// + /// Message to be sent. + /// Public Address of signer. public EthSignMessage(string message, string address) : base(new string[] { message, address }) { } + /// + /// Initializes a new instance of the class used by json.net. + /// Preserved for Unity using ChainSafe.Gaming.Unity/link.xml. + /// public EthSignMessage() { } diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTransaction.cs b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTransaction.cs index 3afc6e41f..01c08682d 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTransaction.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTransaction.cs @@ -5,15 +5,26 @@ namespace ChainSafe.Gaming.WalletConnect.Methods { + /// + /// Sign Transaction Wallet Connect Json RPC method params. + /// [RpcMethod("eth_signTransaction")] [RpcRequestOptions(Clock.ONE_MINUTE, 99996)] public class EthSignTransaction : List { + /// + /// Initializes a new instance of the class. + /// + /// Transaction to be signed. public EthSignTransaction(params TransactionModel[] transactions) : base(transactions) { } + /// + /// Initializes a new instance of the class used by json.net. + /// Preserved for Unity using ChainSafe.Gaming.Unity/link.xml. + /// public EthSignTransaction() { } diff --git a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTypedData.cs b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTypedData.cs index 84288cf78..dbd386636 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTypedData.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Methods/EthSignTypedData.cs @@ -6,10 +6,20 @@ namespace ChainSafe.Gaming.WalletConnect.Methods { + /// + /// Sign Typed Data Wallet Connect Json RPC method params. + /// + /// Type of data to be signed. [RpcMethod("eth_signTypedData")] [RpcRequestOptions(Clock.ONE_MINUTE, 99998)] public class EthSignTypedData : List { + /// + /// Initializes a new instance of the class. + /// + /// Public address of signer. + /// Serializable domain for Json RPC. + /// Typed Data to be signed. public EthSignTypedData(string address, SerializableDomain domain, TStruct message) : base(new object[] { @@ -19,6 +29,10 @@ public EthSignTypedData(string address, SerializableDomain domain, TStruct messa { } + /// + /// Initializes a new instance of the class used by json.net. + /// Preserved for Unity using ChainSafe.Gaming.Unity/link.xml. + /// public EthSignTypedData() { } diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/ChainModel.cs b/src/ChainSafe.Gaming.WalletConnect/Models/ChainModel.cs index aac93bbd1..1111b1f19 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/ChainModel.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Models/ChainModel.cs @@ -1,9 +1,21 @@ namespace ChainSafe.Gaming.WalletConnect.Models { + /// + /// Chain model containing fields used for Wallet Connect. + /// public class ChainModel { + /// + /// Default namespace for EVM. + /// public const string EvmNamespace = "eip155"; + /// + /// Initializes a new instance of the class. + /// + /// Chain Namespace - example "eip155:" for EVMs. + /// Chain Id. + /// Name of the network. public ChainModel(string chainNamespace, string chainId, string name) { ChainNamespace = chainNamespace; @@ -13,12 +25,24 @@ public ChainModel(string chainNamespace, string chainId, string name) Name = name; } + /// + /// Chain Namespace - example "eip155:" for EVMs. + /// public string ChainNamespace { get; private set; } + /// + /// Chain Id. + /// public string ChainId { get; private set; } + /// + /// Name of the network. + /// public string Name { get; private set; } + /// + /// Full chain Id, together with . + /// public string FullChainId => $"{ChainNamespace}:{ChainId}"; } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/ImageUrlsModel.cs b/src/ChainSafe.Gaming.WalletConnect/Models/ImageUrlsModel.cs index d57b2200e..ae5a74e28 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/ImageUrlsModel.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Models/ImageUrlsModel.cs @@ -2,14 +2,26 @@ namespace ChainSafe.Gaming.WalletConnect.Models { + /// + /// Wallet Connect Model used in for Wallet's image url if any. + /// public class ImageUrlsModel { + /// + /// Small size wallet icon image url. + /// [JsonProperty("sm")] public string SmallUrl { get; private set; } + /// + /// Medium size wallet icon image url. + /// [JsonProperty("md")] public string MediumUrl { get; private set; } + /// + /// Large size wallet icon image url. + /// [JsonProperty("lg")] public string LargeUrl { get; private set; } } diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/TransactionModel.cs b/src/ChainSafe.Gaming.WalletConnect/Models/TransactionModel.cs index 1d5fbec72..31673cfc2 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/TransactionModel.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Models/TransactionModel.cs @@ -2,26 +2,50 @@ namespace ChainSafe.Gaming.WalletConnect.Models { + /// + /// Transaction Model used for Wallet Connect Json RPC params, see https://docs.walletconnect.com/advanced/rpc-reference/ethereum-rpc#eth_sendtransaction. + /// public class TransactionModel { + /// + /// Transaction Sender's public address. + /// [JsonProperty("from")] public string From { get; set; } + /// + /// Transaction Receiver's public address. + /// [JsonProperty("to")] public string To { get; set; } + /// + /// Gas fee for transaction in Hex Value. + /// [JsonProperty("gas", NullValueHandling = NullValueHandling.Ignore)] public string Gas { get; set; } + /// + /// Price of in Hex Value. + /// [JsonProperty("gasPrice", NullValueHandling = NullValueHandling.Ignore)] public string GasPrice { get; set; } + /// + /// Amount to be sent in Hex Value. + /// [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] public string Value { get; set; } + /// + /// Transaction Data if any. + /// [JsonProperty("data")] public string Data { get; set; } + /// + /// Nonce in Hex Value. + /// [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] public string Nonce { get; set; } } diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/TypedDataModel.cs b/src/ChainSafe.Gaming.WalletConnect/Models/TypedDataModel.cs index b1af5237e..7e1c95027 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/TypedDataModel.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Models/TypedDataModel.cs @@ -7,10 +7,19 @@ namespace ChainSafe.Gaming.WalletConnect.Models { + /// + /// Typed data model for signing typed data using Wallet Connect JsonRPC, see https://docs.walletconnect.com/advanced/rpc-reference/ethereum-rpc#eth_signtypeddata. + /// + /// Type of Data to be signed. [Serializable] [JsonObject(MemberSerialization.OptIn)] public struct TypedDataModel { + /// + /// Initializes a new instance of the struct. + /// + /// Domain for Typed Data that's serializable by json.net. + /// Typed data to be signed. public TypedDataModel(SerializableDomain domain, TStruct message) { Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(SerializableDomain), typeof(TStruct)); @@ -27,15 +36,27 @@ public TypedDataModel(SerializableDomain domain, TStruct message) Message = message; } + /// + /// Member types for Wallet Connect used in json RPC params. + /// [JsonProperty("types")] public Dictionary Types { get; private set; } + /// + /// Primary type used for Wallet Connect in json RPC params. + /// [JsonProperty("primaryType")] public string PrimaryType { get; private set; } + /// + /// Domain that's serializable by json.net. + /// [JsonProperty("domain")] public SerializableDomain Domain { get; private set; } + /// + /// Data to be signed. + /// [JsonProperty("message")] public TStruct Message { get; private set; } } diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/WalletConnectWalletModel.cs b/src/ChainSafe.Gaming.WalletConnect/Models/WalletConnectWalletModel.cs index 6323d075c..c54160e03 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/WalletConnectWalletModel.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Models/WalletConnectWalletModel.cs @@ -6,24 +6,42 @@ namespace ChainSafe.Gaming.WalletConnect.Models { + /// + /// Wallet Connects wallet model used for identifying and redirecting wallets. + /// public class WalletConnectWalletModel { + /// + /// Name of the wallet. + /// [JsonProperty("name")] public string Name { get; private set; } + /// + /// for mobile platforms. + /// [JsonProperty("mobile")] public WalletLinkModel Mobile { get; private set; } + /// + /// for desktop platforms. + /// [JsonProperty("desktop")] public WalletLinkModel Desktop { get; private set; } + /// + /// wallet icons urls. + /// [JsonProperty("image_url")] public ImageUrlsModel Images { get; private set; } - public void OpenDeeplink(ConnectedData data, IOperatingSystemMediator operatingSystemMediator) + /// + /// Open Wallet to connect with using Uri from . + /// + /// Uri from used for connecting to a wallet. + /// Operating System for current platform. + public void OpenDeeplink(string uri, IOperatingSystemMediator operatingSystemMediator) { - string uri = data.Uri; - switch (operatingSystemMediator.Platform) { case Platform.Android: @@ -33,7 +51,7 @@ public void OpenDeeplink(ConnectedData data, IOperatingSystemMediator operatingS case Platform.IOS: case Platform.Desktop: case Platform.Editor: - uri = GetDeeplink(data.Uri, operatingSystemMediator.IsMobilePlatform); + uri = GetDeeplink(uri, operatingSystemMediator.IsMobilePlatform); break; default: @@ -88,6 +106,10 @@ private string AddDeeplinkParams(string url, string uri) return url; } + /// + /// Opens wallet by using deeplink. + /// + /// Operating System for current platform. public void OpenWallet(IOperatingSystemMediator operatingSystemMediator) { bool isMobilePlatform = operatingSystemMediator.IsMobilePlatform; diff --git a/src/ChainSafe.Gaming.WalletConnect/Models/WalletLinkModel.cs b/src/ChainSafe.Gaming.WalletConnect/Models/WalletLinkModel.cs index 0a0b69536..ba2264433 100644 --- a/src/ChainSafe.Gaming.WalletConnect/Models/WalletLinkModel.cs +++ b/src/ChainSafe.Gaming.WalletConnect/Models/WalletLinkModel.cs @@ -2,11 +2,22 @@ namespace ChainSafe.Gaming.WalletConnect.Models { + /// + /// Wallet linking model used for opening/redirecting to wallets using a deeplink from either a Native or a Universal/http protocol. + /// public struct WalletLinkModel { + /// + /// Native protocol deeplink for redirecting to wallet. + /// If available this redirects without opening a browser. + /// [JsonProperty("native")] public string NativeProtocol { get; private set; } + /// + /// Universal url deeplink for redirecting to wallet. + /// If available this opens a browser that triggers a native deeplink. + /// [JsonProperty("universal")] public string UniversalUrl { get; private set; } } diff --git a/src/ChainSafe.Gaming.WalletConnect/WCLogWriter.cs b/src/ChainSafe.Gaming.WalletConnect/WCLogWriter.cs index 58bf8eae4..c651c8a5a 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WCLogWriter.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WCLogWriter.cs @@ -5,19 +5,38 @@ namespace ChainSafe.Gaming.WalletConnect { + /// + /// Writes Wallet Connect logs to platform. + /// public class WCLogWriter : ILogger { private readonly ILogWriter logWriter; + /// + /// Initializes a new instance of the class. + /// + /// Log Writer used for logging. public WCLogWriter(ILogWriter logWriter) { this.logWriter = logWriter; } + /// + /// Log Message. + /// + /// Message to be logged. public void Log(string message) => logWriter.Log(message); + /// + /// Log Error. + /// + /// Error message to be logged. public void LogError(string message) => logWriter.LogError(message); + /// + /// Log Exception as Error. + /// + /// Exception to be logged. public void LogError(Exception e) => logWriter.LogError($"{e} {e.Message} {e.StackTrace}"); } } \ No newline at end of file diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs index a8e0e90d2..1993aceb3 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectConfig.cs @@ -8,56 +8,123 @@ namespace ChainSafe.Gaming.WalletConnect { + /// + /// Used for configuring a wallet connect session. + /// + /// Serialize fields explicitly or only ones with [JsonProperty] attribute used for restoring/renewing a session. [Serializable] [JsonObject(MemberSerialization.OptIn)] public class WalletConnectConfig { + /// + /// Delegate used for when a session to connect to a wallet is initialized. + /// public delegate void Connected(ConnectedData connectedData); + /// + /// Delegate used for when a connection session is approved from wallet. + /// public delegate void SessionApproved(SessionStruct session); + /// + /// Event that's triggered when a session to connect to a wallet is initialized. + /// public event Connected OnConnected; + /// + /// Event triggered when a connection session is approved from wallet. + /// public event SessionApproved OnSessionApproved; + /// + /// Wallet Connect Project Id, can be found in Wallet Connect web dashboard. + /// public string ProjectId { get; set; } + /// + /// Wallet Connect Project Name. + /// public string ProjectName { get; set; } + /// + /// Topic for any saved Wallet Connect sessions. + /// Used for restoring already existing sessions. + /// [JsonProperty] public string SavedSessionTopic { get; set; } + /// + /// Storage directory for Wallet Connect json file. + /// This file is generally used for restoring sessions. + /// public string StoragePath { get; set; } + /// + /// Wallet Connect platform and usage context. + /// For example "unity-game" is used in a Unity Made Game. + /// public string BaseContext { get; set; } + /// + /// Chain of wallet to connect to, eg - Goerli. + /// Used for specifying required namespaces for connecting to wallet. + /// public ChainModel Chain { get; set; } + /// + /// Metadata for dapp/project. + /// This will be displayed to wallet user when connecting and on other wallet connect prompts. + /// public Metadata Metadata { get; set; } + /// + /// If wallet is installed on the same device as dapp should it redirect to wallet for any and all prompts. + /// This uses deeplink-ing and might not work and/or be available for every wallet and/or platform. + /// [JsonProperty] public bool RedirectToWallet { get; set; } + /// + /// Keep renewing session when expired. + /// [JsonProperty] public bool KeepSessionAlive { get; set; } + /// + /// Default wallet that's being used, or a session is connected to. + /// This works together with . + /// [JsonProperty] public WalletConnectWalletModel DefaultWallet { get; set; } + /// + /// All wallets supported by Wallet Connect, see https://registry.walletconnect.org/data/wallets.json. + /// public Dictionary SupportedWallets { get; set; } + /// + /// Set to true if running tests. + /// public bool Testing { get; set; } = false; + /// + /// Public Address used for testing. + /// This is only relevant if is set to true. + /// public string TestWalletAddress { get; set; } = null; + /// + /// if is set to true replace this with already made response hash before making the request. + /// This is used to skip required approval from a user when testing. + /// public string TestResponse { get; set; } = string.Empty; - public void InvokeConnected(ConnectedData connectedData) + internal void InvokeConnected(ConnectedData connectedData) { OnConnected?.Invoke(connectedData); } - public void InvokeSessionApproved(SessionStruct session) + internal void InvokeSessionApproved(SessionStruct session) { OnSessionApproved?.Invoke(session); } diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectCustomProvider.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectCustomProvider.cs index 031256655..2a13cffa7 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectCustomProvider.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectCustomProvider.cs @@ -21,12 +21,21 @@ namespace ChainSafe.Gaming.WalletConnect { + /// + /// Concrete implementation of . + /// public class WalletConnectCustomProvider : IWalletConnectCustomProvider, ILifecycleParticipant { private readonly IOperatingSystemMediator operatingSystem; private readonly ILogWriter logWriter; private readonly WalletConnectConfig config; + /// + /// Initializes a new instance of the class. + /// + /// Wallet connect configuration used to pass values to this provider. + /// Operating system mediator used for passing platform information and opening a deeplink. + /// Log writer used for logging messages to platform. public WalletConnectCustomProvider(WalletConnectConfig config, IOperatingSystemMediator operatingSystem, ILogWriter logWriter) { this.operatingSystem = operatingSystem; @@ -34,17 +43,34 @@ public WalletConnectCustomProvider(WalletConnectConfig config, IOperatingSystemM this.logWriter = logWriter; } - // static to not destroy client session on logout/TerminateAsync, just disconnect instead + /// + /// Connected client. + /// It's static to not destroy client session on logout/TerminateAsync, just disconnect instead. + /// public static WalletConnectSignClient SignClient { get; private set; } + /// + /// Wallet Connect Core. + /// public WalletConnectCore Core { get; private set; } + /// + /// Connected session if any. + /// public SessionStruct Session { get; private set; } + /// + /// ConnectedData used to create a connection/. + /// public ConnectedData ConnectedData { get; private set; } private bool SessionExpired => Session.Expiry != null && Clock.IsExpired((long)Session.Expiry); + /// + /// Implementation of . + /// Lifetime event method, called during initialization. + /// + /// async awaitable task. public ValueTask WillStartAsync() { return new ValueTask(Task.CompletedTask); @@ -87,7 +113,12 @@ private async Task Initialize() }); } - // Connect to wallet and return address of connected wallet. + /// + /// Implementation of . + /// Connect to a wallet and create a . + /// + /// Address of connected wallet. + /// Exception Thrown if connection fails. public async Task Connect() { await Initialize(); @@ -153,7 +184,7 @@ public async Task Connect() { try { - config.DefaultWallet.OpenDeeplink(ConnectedData, operatingSystem); + config.DefaultWallet.OpenDeeplink(ConnectedData.Uri, operatingSystem); } catch (Exception e) { @@ -226,6 +257,11 @@ public async Task Connect() return address; } + /// + /// Implementation of . + /// Lifetime event method, called during . + /// + /// async awaitable task. public ValueTask WillStopAsync() { if (!config.KeepSessionAlive) @@ -237,6 +273,15 @@ public ValueTask WillStopAsync() return new ValueTask(Task.CompletedTask); } + /// + /// Implementation of . + /// Make a json RPC request using Wallet Connect. + /// + /// Request data or params. Data class/struct must be decorated with a . + /// Time for request to expire. + /// Request data type or params. + /// Response string hash. + /// Exception thrown if request fails. public async Task Request(T data, long? expiry = null) { // if testing skip making request @@ -339,6 +384,11 @@ private FileSystemStorage BuildStorage() return new FileSystemStorage(path); } + /// + /// Implementation of . + /// Disconnects if it exists. + /// + /// Async awaitable task. public async Task Disconnect() { WCLogger.Log("Disconnecting Wallet Connect session..."); diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectProviderExtensions.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectProviderExtensions.cs index acc85cf3c..d90499e52 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectProviderExtensions.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectProviderExtensions.cs @@ -5,11 +5,16 @@ namespace ChainSafe.Gaming.WalletConnect { + /// + /// extension methods. + /// public static class WalletConnectProviderExtensions { /// - /// Binds Web implementation of EVM Provider to Web3. + /// Binds implementation of as and to Web3 as a service. /// + /// Service collection to bind implementations to. + /// Wallet Connect Configuration. /// The same service collection that was passed in. This enables fluent style. public static IWeb3ServiceCollection UseWalletConnect(this IWeb3ServiceCollection collection, WalletConnectConfig config) { diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs index c4c284a74..8d13f9baf 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectSigner.cs @@ -1,43 +1,39 @@ -using System; -using System.IO; -using System.Linq; using System.Threading.Tasks; using ChainSafe.Gaming.Evm.Signers; -using ChainSafe.Gaming.Evm.Transactions; using ChainSafe.Gaming.WalletConnect.Methods; -using ChainSafe.Gaming.WalletConnect.Models; using ChainSafe.Gaming.Web3; using ChainSafe.Gaming.Web3.Core; using ChainSafe.Gaming.Web3.Core.Debug; using ChainSafe.Gaming.Web3.Core.Evm; -using ChainSafe.Gaming.Web3.Environment; -using WalletConnectSharp.Common.Logging; -using WalletConnectSharp.Common.Model.Errors; -using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Core; -using WalletConnectSharp.Core.Models; -using WalletConnectSharp.Core.Models.Relay; -using WalletConnectSharp.Network.Models; -using WalletConnectSharp.Sign; -using WalletConnectSharp.Sign.Models; -using WalletConnectSharp.Sign.Models.Engine; -using WalletConnectSharp.Storage; namespace ChainSafe.Gaming.WalletConnect { + /// + /// Implementation of for Wallet Connect. + /// public class WalletConnectSigner : ISigner, ILifecycleParticipant { private readonly IWalletConnectCustomProvider walletConnectCustomProvider; private readonly WalletConnectConfig config; + private string address; + + /// + /// Initializes a new instance of the class. + /// + /// Wallet Connect Provider that connects wallet and makes jsom RPC requests via Wallet Connect. + /// Wallet Connect config for passing configuration values. public WalletConnectSigner(IWalletConnectCustomProvider walletConnectCustomProvider, WalletConnectConfig config) { this.walletConnectCustomProvider = walletConnectCustomProvider; this.config = config; } - private string Address { get; set; } - + /// + /// Implementation of . + /// Lifetime event method, called during initialization. + /// + /// async awaitable task. public async ValueTask WillStartAsync() { // if testing just don't initialize wallet connect @@ -45,34 +41,53 @@ public async ValueTask WillStartAsync() { config.TestWalletAddress?.AssertIsPublicAddress(nameof(config.TestWalletAddress)); - Address = config.TestWalletAddress; + address = config.TestWalletAddress; return; } // get address by connecting - Address = await walletConnectCustomProvider.Connect(); + address = await walletConnectCustomProvider.Connect(); } + /// + /// Implementation of . + /// Lifetime event method, called during . + /// + /// async awaitable task. public ValueTask WillStopAsync() { return new ValueTask(Task.CompletedTask); } + /// + /// Implementation of . + /// Get public address of connected client. + /// + /// Wallet address of connected client. + /// Throws exception if getting address fails. public Task GetAddress() { - if (!AddressExtensions.IsPublicAddress(Address)) + if (!AddressExtensions.IsPublicAddress(address)) { throw new Web3Exception( - $"Public address recovered from signature is not valid. Public address: {Address}"); + $"Public address recovered from signature is not valid. Public address: {address}"); } - return Task.FromResult(Address); + return Task.FromResult(address); } + /// + /// Implementation of . + /// Sign message using Wallet Connect. + /// This prompts user to sign a message on a connected wallet. + /// + /// Message to sign. + /// Hash response of a successfully signed message. + /// Throws Exception if signing message fails. public async Task SignMessage(string message) { - var requestData = new EthSignMessage(message, Address); + var requestData = new EthSignMessage(message, address); string hash = await walletConnectCustomProvider.Request(requestData); @@ -93,9 +108,18 @@ bool ValidateResponse(string response) } } + /// + /// Implementation of . + /// Sign Typed Data using wallet connect. + /// + /// A serializable domain separator. + /// Data to be signed. + /// Data type of data to be signed. + /// Hash response of a successfully signed typed data. + /// Throws Exception if signing typed data fails. public async Task SignTypedData(SerializableDomain domain, TStructType message) { - var requestData = new EthSignTypedData(Address, domain, message); + var requestData = new EthSignTypedData(address, domain, message); string hash = await walletConnectCustomProvider.Request(requestData); diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSignerExtensions.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectSignerExtensions.cs index fb8c94378..806bd95e1 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectSignerExtensions.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectSignerExtensions.cs @@ -1,17 +1,18 @@ 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; -using Microsoft.Extensions.DependencyInjection.Extensions; namespace ChainSafe.Gaming.WalletConnect { + /// + /// extension methods. + /// public static class WalletConnectSignerExtensions { /// - /// Binds Web implementation of EVM Provider to Web3. + /// 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 UseWalletConnectSigner(this IWeb3ServiceCollection collection) { diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs index be782f34d..5b409fcc8 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutor.cs @@ -1,23 +1,29 @@ using System.Threading.Tasks; using ChainSafe.Gaming.Evm.Providers; -using ChainSafe.Gaming.Evm.Signers; using ChainSafe.Gaming.Evm.Transactions; using ChainSafe.Gaming.WalletConnect.Methods; using ChainSafe.Gaming.WalletConnect.Models; using ChainSafe.Gaming.Web3; using ChainSafe.Gaming.Web3.Core; using ChainSafe.Gaming.Web3.Core.Evm; -using Newtonsoft.Json; using WalletConnectSharp.Common.Logging; namespace ChainSafe.Gaming.WalletConnect { + /// + /// Implementation of for Wallet Connect. + /// public class WalletConnectTransactionExecutor : ITransactionExecutor, ILifecycleParticipant { private readonly IWalletConnectCustomProvider walletConnectCustomProvider; private readonly IRpcProvider rpcProvider; + /// + /// Initializes a new instance of the class. + /// + /// Wallet Connect Provider that connects wallet and makes jsom RPC requests via Wallet Connect. + /// Provider for getting transaction receipt. public WalletConnectTransactionExecutor(IWalletConnectCustomProvider walletConnectCustomProvider, IRpcProvider rpcProvider) { this.walletConnectCustomProvider = walletConnectCustomProvider; @@ -25,10 +31,28 @@ public WalletConnectTransactionExecutor(IWalletConnectCustomProvider walletConne this.rpcProvider = rpcProvider; } + /// + /// Implementation of . + /// Lifetime event method, called during initialization. + /// + /// async awaitable task. public ValueTask WillStartAsync() => new ValueTask(Task.CompletedTask); + /// + /// Implementation of . + /// Lifetime event method, called during . + /// + /// async awaitable task. public ValueTask WillStopAsync() => new ValueTask(Task.CompletedTask); + /// + /// Implementation of . + /// Send a transaction using Wallet Connect. + /// This prompts user to approve a transaction on a connected wallet. + /// + /// Transaction to send. + /// Hash response of a successfully executed transaction. + /// Throws Exception if executing transaction fails. public async Task SendTransaction(TransactionRequest transaction) { EthSendTransaction requestData = new EthSendTransaction(new TransactionModel @@ -52,6 +76,7 @@ public async Task SendTransaction(TransactionRequest transa WCLogger.Log($"Transaction executed with hash {hash}"); + // TODO use wallet connect to get receipt if possible. return await rpcProvider.GetTransaction(hash); } } diff --git a/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutorExtensions.cs b/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutorExtensions.cs index 9bb64d177..a07e10bf6 100644 --- a/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutorExtensions.cs +++ b/src/ChainSafe.Gaming.WalletConnect/WalletConnectTransactionExecutorExtensions.cs @@ -4,11 +4,15 @@ namespace ChainSafe.Gaming.WalletConnect { + /// + /// extension methods. + /// public static class WalletConnectTransactionExecutorExtensions { /// - /// Binds Web implementation of EVM Provider to Web3. + /// 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 UseWalletConnectTransactionExecutor(this IWeb3ServiceCollection collection) {