diff --git a/CryptoExchange.Net/Authentication/AuthenticationProvider.cs b/CryptoExchange.Net/Authentication/AuthenticationProvider.cs
index 65551ba..e3517a7 100644
--- a/CryptoExchange.Net/Authentication/AuthenticationProvider.cs
+++ b/CryptoExchange.Net/Authentication/AuthenticationProvider.cs
@@ -74,6 +74,17 @@ namespace CryptoExchange.Net.Authentication
return encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
}
+ ///
+ /// SHA256 sign the data and return the bytes
+ ///
+ ///
+ ///
+ protected static byte[] SignSHA256Bytes(byte[] data)
+ {
+ using var encryptor = SHA256.Create();
+ return encryptor.ComputeHash(data);
+ }
+
///
/// SHA256 sign the data and return the hash
///
@@ -87,6 +98,19 @@ namespace CryptoExchange.Net.Authentication
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
}
+ ///
+ /// SHA256 sign the data and return the hash
+ ///
+ /// Data to sign
+ /// String type
+ ///
+ protected static string SignSHA256(byte[] data, SignOutputType? outputType = null)
+ {
+ using var encryptor = SHA256.Create();
+ var resultBytes = encryptor.ComputeHash(data);
+ return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
+ }
+
///
/// SHA384 sign the data and return the hash
///
@@ -100,6 +124,41 @@ namespace CryptoExchange.Net.Authentication
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
}
+ ///
+ /// SHA384 sign the data and return the hash
+ ///
+ /// Data to sign
+ /// String type
+ ///
+ protected static string SignSHA384(byte[] data, SignOutputType? outputType = null)
+ {
+ using var encryptor = SHA384.Create();
+ var resultBytes = encryptor.ComputeHash(data);
+ return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
+ }
+
+ ///
+ /// SHA384 sign the data and return the hash
+ ///
+ /// Data to sign
+ ///
+ protected static byte[] SignSHA384Bytes(string data)
+ {
+ using var encryptor = SHA384.Create();
+ return encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
+ }
+
+ ///
+ /// SHA384 sign the data and return the hash
+ ///
+ /// Data to sign
+ ///
+ protected static byte[] SignSHA384Bytes(byte[] data)
+ {
+ using var encryptor = SHA384.Create();
+ return encryptor.ComputeHash(data);
+ }
+
///
/// SHA512 sign the data and return the hash
///
@@ -113,6 +172,41 @@ namespace CryptoExchange.Net.Authentication
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
}
+ ///
+ /// SHA512 sign the data and return the hash
+ ///
+ /// Data to sign
+ /// String type
+ ///
+ protected static string SignSHA512(byte[] data, SignOutputType? outputType = null)
+ {
+ using var encryptor = SHA512.Create();
+ var resultBytes = encryptor.ComputeHash(data);
+ return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
+ }
+
+ ///
+ /// SHA512 sign the data and return the hash
+ ///
+ /// Data to sign
+ ///
+ protected static byte[] SignSHA512Bytes(string data)
+ {
+ using var encryptor = SHA512.Create();
+ return encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
+ }
+
+ ///
+ /// SHA512 sign the data and return the hash
+ ///
+ /// Data to sign
+ ///
+ protected static byte[] SignSHA512Bytes(byte[] data)
+ {
+ using var encryptor = SHA512.Create();
+ return encryptor.ComputeHash(data);
+ }
+
///
/// MD5 sign the data and return the hash
///
@@ -127,28 +221,70 @@ namespace CryptoExchange.Net.Authentication
}
///
- /// HMACSHA256 sign the data and return the hash
+ /// MD5 sign the data and return the hash
+ ///
+ /// Data to sign
+ /// String type
+ ///
+ protected static string SignMD5(byte[] data, SignOutputType? outputType = null)
+ {
+ using var encryptor = MD5.Create();
+ var resultBytes = encryptor.ComputeHash(data);
+ return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
+ }
+
+ ///
+ /// MD5 sign the data and return the hash
+ ///
+ /// Data to sign
+ ///
+ protected static byte[] SignMD5Bytes(string data)
+ {
+ using var encryptor = MD5.Create();
+ return encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
+ }
+
+ ///
+ /// HMACSHA512 sign the data and return the hash
///
/// Data to sign
/// String type
///
protected string SignHMACSHA256(string data, SignOutputType? outputType = null)
+ => SignHMACSHA256(Encoding.UTF8.GetBytes(data), outputType);
+
+ ///
+ /// HMACSHA256 sign the data and return the hash
+ ///
+ /// Data to sign
+ /// String type
+ ///
+ protected string SignHMACSHA256(byte[] data, SignOutputType? outputType = null)
{
using var encryptor = new HMACSHA256(_sBytes);
- var resultBytes = encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
+ var resultBytes = encryptor.ComputeHash(data);
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
}
+ ///
+ /// HMACSHA512 sign the data and return the hash
+ ///
+ /// Data to sign
+ /// String type
+ ///
+ protected string SignHMACSHA384(string data, SignOutputType? outputType = null)
+ => SignHMACSHA384(Encoding.UTF8.GetBytes(data), outputType);
+
///
/// HMACSHA384 sign the data and return the hash
///
/// Data to sign
/// String type
///
- protected string SignHMACSHA384(string data, SignOutputType? outputType = null)
+ protected string SignHMACSHA384(byte[] data, SignOutputType? outputType = null)
{
using var encryptor = new HMACSHA384(_sBytes);
- var resultBytes = encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
+ var resultBytes = encryptor.ComputeHash(data);
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
}
@@ -182,7 +318,46 @@ namespace CryptoExchange.Net.Authentication
///
protected string SignRSASHA256(byte[] data, SignOutputType? outputType = null)
{
- using var rsa = RSA.Create();
+ using var rsa = CreateRSA();
+ using var sha256 = SHA256.Create();
+ var hash = sha256.ComputeHash(data);
+ var resultBytes = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+ return outputType == SignOutputType.Base64? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
+ }
+
+ ///
+ /// SHA384 sign the data
+ ///
+ ///
+ ///
+ ///
+ protected string SignRSASHA384(byte[] data, SignOutputType? outputType = null)
+ {
+ using var rsa = CreateRSA();
+ using var sha384 = SHA384.Create();
+ var hash = sha384.ComputeHash(data);
+ var resultBytes = rsa.SignHash(hash, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
+ return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
+ }
+
+ ///
+ /// SHA512 sign the data
+ ///
+ ///
+ ///
+ ///
+ protected string SignRSASHA512(byte[] data, SignOutputType? outputType = null)
+ {
+ using var rsa = CreateRSA();
+ using var sha512 = SHA512.Create();
+ var hash = sha512.ComputeHash(data);
+ var resultBytes = rsa.SignHash(hash, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
+ return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
+ }
+
+ private RSA CreateRSA()
+ {
+ var rsa = RSA.Create();
if (_credentials.CredentialType == ApiCredentialsType.RsaPem)
{
#if NETSTANDARD2_1_OR_GREATER
@@ -209,30 +384,7 @@ namespace CryptoExchange.Net.Authentication
throw new Exception("Invalid credentials type");
}
- using var sha256 = SHA256.Create();
- var hash = sha256.ComputeHash(data);
- var resultBytes = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
- return outputType == SignOutputType.Base64? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
- }
-
- ///
- /// Sign a string
- ///
- ///
- ///
- public virtual string Sign(string toSign)
- {
- return toSign;
- }
-
- ///
- /// Sign a byte array
- ///
- ///
- ///
- public virtual byte[] Sign(byte[] toSign)
- {
- return toSign;
+ return rsa;
}
///
diff --git a/CryptoExchange.Net/Clients/BaseApiClient.cs b/CryptoExchange.Net/Clients/BaseApiClient.cs
index dbdd27f..55072c7 100644
--- a/CryptoExchange.Net/Clients/BaseApiClient.cs
+++ b/CryptoExchange.Net/Clients/BaseApiClient.cs
@@ -7,6 +7,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using CryptoExchange.Net.Authentication;
+using CryptoExchange.Net.Converters;
using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Options;
@@ -78,13 +79,9 @@ namespace CryptoExchange.Net
public bool OutputOriginalData { get; }
///
- /// A default serializer
+ /// The default serializer
///
- private static readonly JsonSerializer _defaultSerializer = JsonSerializer.Create(new JsonSerializerSettings
- {
- DateTimeZoneHandling = DateTimeZoneHandling.Utc,
- Culture = CultureInfo.InvariantCulture
- });
+ protected virtual JsonSerializer DefaultSerializer { get; set; } = JsonSerializer.Create(SerializerOptions.Default);
///
/// Api options
@@ -204,7 +201,7 @@ namespace CryptoExchange.Net
///
protected CallResult Deserialize(JToken obj, JsonSerializer? serializer = null, int? requestId = null)
{
- serializer ??= _defaultSerializer;
+ serializer ??= DefaultSerializer;
try
{
@@ -242,7 +239,7 @@ namespace CryptoExchange.Net
///
protected async Task> DeserializeAsync(Stream stream, JsonSerializer? serializer = null, int? requestId = null, long? elapsedMilliseconds = null)
{
- serializer ??= _defaultSerializer;
+ serializer ??= DefaultSerializer;
string? data = null;
try
diff --git a/CryptoExchange.Net/Clients/RestApiClient.cs b/CryptoExchange.Net/Clients/RestApiClient.cs
index 6b894c5..769c381 100644
--- a/CryptoExchange.Net/Clients/RestApiClient.cs
+++ b/CryptoExchange.Net/Clients/RestApiClient.cs
@@ -273,7 +273,7 @@ namespace CryptoExchange.Net
if (response.IsSuccessStatusCode)
{
// If we have to manually parse error responses (can't rely on HttpStatusCode) we'll need to read the full
- // response before being able to deserialize it into the resulting type since we don't know if it an error response or data
+ // response before being able to deserialize it into the resulting type since we don't know if its an error response or data
if (manualParseError)
{
using var reader = new StreamReader(responseStream);
diff --git a/CryptoExchange.Net/Converters/BoolConverter.cs b/CryptoExchange.Net/Converters/BoolConverter.cs
index fb8431f..92b679e 100644
--- a/CryptoExchange.Net/Converters/BoolConverter.cs
+++ b/CryptoExchange.Net/Converters/BoolConverter.cs
@@ -47,6 +47,7 @@ namespace CryptoExchange.Net.Converters
case "n":
case "0":
case "off":
+ case "-1":
return false;
}
diff --git a/CryptoExchange.Net/Converters/EnumConverter.cs b/CryptoExchange.Net/Converters/EnumConverter.cs
index 1da595a..9188c57 100644
--- a/CryptoExchange.Net/Converters/EnumConverter.cs
+++ b/CryptoExchange.Net/Converters/EnumConverter.cs
@@ -33,7 +33,7 @@ namespace CryptoExchange.Net.Converters
///
public override bool CanConvert(Type objectType)
{
- return objectType.IsEnum;
+ return objectType.IsEnum || Nullable.GetUnderlyingType(objectType)?.IsEnum == true;
}
///
diff --git a/CryptoExchange.Net/Converters/SerializerOptions.cs b/CryptoExchange.Net/Converters/SerializerOptions.cs
new file mode 100644
index 0000000..2e71a5d
--- /dev/null
+++ b/CryptoExchange.Net/Converters/SerializerOptions.cs
@@ -0,0 +1,35 @@
+using Newtonsoft.Json;
+using System.Globalization;
+
+namespace CryptoExchange.Net.Converters
+{
+ ///
+ /// Serializer options
+ ///
+ public static class SerializerOptions
+ {
+ ///
+ /// Json serializer settings which includes the EnumConverter, DateTimeConverter and BoolConverter
+ ///
+ public static JsonSerializerSettings WithConverters => new JsonSerializerSettings
+ {
+ DateTimeZoneHandling = DateTimeZoneHandling.Utc,
+ Culture = CultureInfo.InvariantCulture,
+ Converters =
+ {
+ new EnumConverter(),
+ new DateTimeConverter(),
+ new BoolConverter()
+ }
+ };
+
+ ///
+ /// Default json serializer settings
+ ///
+ public static JsonSerializerSettings Default => new JsonSerializerSettings
+ {
+ DateTimeZoneHandling = DateTimeZoneHandling.Utc,
+ Culture = CultureInfo.InvariantCulture
+ };
+ }
+}
diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj
index 6451da5..16a8b04 100644
--- a/CryptoExchange.Net/CryptoExchange.Net.csproj
+++ b/CryptoExchange.Net/CryptoExchange.Net.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0;netstandard2.1
diff --git a/CryptoExchange.Net/Objects/ParameterCollection.cs b/CryptoExchange.Net/Objects/ParameterCollection.cs
new file mode 100644
index 0000000..ffcad33
--- /dev/null
+++ b/CryptoExchange.Net/Objects/ParameterCollection.cs
@@ -0,0 +1,172 @@
+using CryptoExchange.Net.Attributes;
+using CryptoExchange.Net.Converters;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace CryptoExchange.Net.Objects
+{
+ ///
+ /// Parameters collection
+ ///
+ public class ParameterCollection : Dictionary
+ {
+ ///
+ /// Add an optional parameter. Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptional(string key, object? value)
+ {
+ if (value != null)
+ Add(key, value);
+ }
+
+ ///
+ /// Add a decimal value as string
+ ///
+ ///
+ ///
+ public void AddString(string key, decimal value)
+ {
+ Add(key, value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a decimal value as string. Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptionalString(string key, decimal? value)
+ {
+ if (value != null)
+ Add(key, value.Value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a int value as string
+ ///
+ ///
+ ///
+ public void AddString(string key, int value)
+ {
+ Add(key, value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a int value as string. Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptionalString(string key, int? value)
+ {
+ if (value != null)
+ Add(key, value.Value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a long value as string
+ ///
+ ///
+ ///
+ public void AddString(string key, long value)
+ {
+ Add(key, value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a long value as string. Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptionalString(string key, long? value)
+ {
+ if (value != null)
+ Add(key, value.Value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a datetime value as milliseconds timestamp
+ ///
+ ///
+ ///
+ public void AddMilliseconds(string key, DateTime value)
+ {
+ Add(key, DateTimeConverter.ConvertToMilliseconds(value));
+ }
+
+ ///
+ /// Add a datetime value as milliseconds timestamp. Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptionalMilliseconds(string key, DateTime? value)
+ {
+ if (value != null)
+ Add(key, DateTimeConverter.ConvertToMilliseconds(value));
+ }
+
+ ///
+ /// Add a datetime value as milliseconds timestamp
+ ///
+ ///
+ ///
+ public void AddMillisecondsString(string key, DateTime value)
+ {
+ Add(key, DateTimeConverter.ConvertToMilliseconds(value).Value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a datetime value as milliseconds timestamp. Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptionalMillisecondsString(string key, DateTime? value)
+ {
+ if (value != null)
+ Add(key, DateTimeConverter.ConvertToMilliseconds(value).Value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Add a datetime value as seconds timestamp
+ ///
+ ///
+ ///
+ public void AddSeconds(string key, DateTime value)
+ {
+ Add(key, DateTimeConverter.ConvertToSeconds(value));
+ }
+
+ ///
+ /// Add a datetime value as seconds timestamp. Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptionalSeconds(string key, DateTime? value)
+ {
+ if (value != null)
+ Add(key, DateTimeConverter.ConvertToSeconds(value));
+ }
+
+ ///
+ /// Add an enum value as the string value as mapped using the
+ ///
+ ///
+ ///
+ public void AddEnum(string key, T value)
+ {
+ Add(key, EnumConverter.GetString(value)!);
+ }
+
+ ///
+ /// Add an enum value as the string value as mapped using the . Not added if value is null
+ ///
+ ///
+ ///
+ public void AddOptionalEnum(string key, T? value)
+ {
+ if (value != null)
+ Add(key, EnumConverter.GetString(value));
+ }
+ }
+}