Skip to content

Commit

Permalink
CryptoExchange.Net testing update (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
JKorf authored May 1, 2024
1 parent 58e14dd commit ac20525
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Bitfinex.Net.UnitTests/Bitfinex.Net.UnitTests.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
Expand Down
78 changes: 33 additions & 45 deletions Bitfinex.Net.UnitTests/BitfinexClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
using Bitfinex.Net.ExtensionMethods;
using CryptoExchange.Net.Objects.Sockets;
using NUnit.Framework.Legacy;
using CryptoExchange.Net.Clients;
using System.Net.Http;
using System.Collections.Generic;
using CryptoExchange.Net.Converters.JsonNet;
using CryptoExchange.Net.Testing.Implementations;

namespace Bitfinex.Net.UnitTests
{
Expand Down Expand Up @@ -49,19 +54,6 @@ public void ProvidingApiCredentials_Should_SaveApiCredentials()
Assert.That(authProvider.GetApiKey() == "TestKey");
}

[Test]
public void SigningString_Should_ReturnCorrectString()
{
// arrange
var authProvider = new BitfinexAuthenticationProvider(new ApiCredentials("TestKey", "TestSecret"), null);

// act
string signed = authProvider.Sign("SomeTestString");

// assert
Assert.That(signed == "9052C73092B21B945BC5859CADBA6A5658E142F021FCB092A72F68E8A0D5E6351CFEBAE52DB9067D4360F796CB520960");
}

[Test]
public async Task MakingAuthv2Call_Should_SendAuthHeaders()
{
Expand All @@ -79,44 +71,40 @@ public async Task MakingAuthv2Call_Should_SendAuthHeaders()
}

[Test]
public void CheckRestInterfaces()
public void CheckSignatureExample1()
{
var assembly = Assembly.GetAssembly(typeof(BitfinexRestClient));
var ignore = new string[] { "IBitfinexClient" };
var clientInterfaces = assembly.GetTypes().Where(t => t.Name.StartsWith("IBitfinexClient") && !ignore.Contains(t.Name));

foreach (var clientInterface in clientInterfaces)
{
var implementation = assembly.GetTypes().Single(t => t.IsAssignableTo(clientInterface) && t != clientInterface);
int methods = 0;
foreach (var method in implementation.GetMethods().Where(m => m.ReturnType.IsAssignableTo(typeof(Task))))
var authProvider = new BitfinexAuthenticationProvider(
new ApiCredentials("hO6oQotzTE0S5FRYze2Jx2wGx7eVnJGMolpA1nZyehsoMgCcgKNWQHd4QgTFZuwl4Zt4xMe2PqGBegWXO4A", "mheO6dR8ovSsxZQCOYEFCtelpuxcWGTfHw7te326y6jOwq5WpvFQ9JNljoTwBXZGv5It07m9RXSPpDQEK2w"),
new TestNonceProvider(1696751141337)
);
var client = (RestApiClient)new BitfinexRestClient().SpotApi;

CryptoExchange.Net.Testing.TestHelpers.CheckSignature(
client,
authProvider,
HttpMethod.Post,
"v2/auth/w/order/submit",
(uriParams, bodyParams, headers) =>
{
return headers["bfx-signature"].ToString();
},
"5bead18437434889be3fda165655289d30ee7433d5cdaa9bffd1c3291ea625971b452ca87c7ed11af4e9c959352ec91a",
new Dictionary<string, object>
{
var interfaceMethod = clientInterface.GetMethod(method.Name, method.GetParameters().Select(p => p.ParameterType).ToArray());
ClassicAssert.NotNull(interfaceMethod, $"Missing interface for method {method.Name} in {implementation.Name} implementing interface {clientInterface.Name}");
methods++;
}
Debug.WriteLine($"{clientInterface.Name} {methods} methods validated");
}
{ "type", "LIMIT" },
{ "symbol", "tBTCUSD" },
{ "price", 15 },
{ "amount", 0.1 },
},
disableOrdering: true);

}

[Test]
public void CheckSocketInterfaces()
public void CheckInterfaces()
{
var assembly = Assembly.GetAssembly(typeof(BitfinexSocketClient));
var clientInterfaces = assembly.GetTypes().Where(t => t.Name.StartsWith("IBitfinexSocketClient"));

foreach (var clientInterface in clientInterfaces)
{
var implementation = assembly.GetTypes().Single(t => t.IsAssignableTo(clientInterface) && t != clientInterface);
int methods = 0;
foreach (var method in implementation.GetMethods().Where(m => m.ReturnType.IsAssignableTo(typeof(Task<CallResult<UpdateSubscription>>))))
{
var interfaceMethod = clientInterface.GetMethod(method.Name, method.GetParameters().Select(p => p.ParameterType).ToArray());
ClassicAssert.NotNull(interfaceMethod, $"Missing interface for method {method.Name} in {implementation.Name} implementing interface {clientInterface.Name}");
methods++;
}
Debug.WriteLine($"{clientInterface.Name} {methods} methods validated");
}
CryptoExchange.Net.Testing.TestHelpers.CheckForMissingRestInterfaces<BitfinexRestClient>();
CryptoExchange.Net.Testing.TestHelpers.CheckForMissingSocketInterfaces<BitfinexSocketClient>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GET
/v2/platform/status
false
[
1 //STATUS
]
18 changes: 18 additions & 0 deletions Bitfinex.Net.UnitTests/Endpoints/Spot/ExchangeData/GetTickers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
GET
/v2/tickers
false
[
[
"tBTCUSD", //SYMBOL
10645, //BID
73.93854271, //BID_SIZE
10647, //ASK
75.22266119, //ASK_SIZE
731.60645389, //DAILY_CHANGE
0.0738, //DAILY_CHANGE_RELATIVE
10644.00645389, //LAST_PRICE
14480.89849423, //VOLUME
10766, //HIGH
9889.1449809 //LOW
]
]
31 changes: 31 additions & 0 deletions Bitfinex.Net.UnitTests/RestRequestTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using NUnit.Framework;
using System.Threading.Tasks;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Objects;
using Bitfinex.Net.Clients;
using CryptoExchange.Net.Testing;

namespace Bitfinex.Net.UnitTests
{
[TestFixture]
public class RestRequestTests
{
[Test]
public async Task ValidateSpotExchangeDataCalls()
{
var client = new BitfinexRestClient(opts =>
{
opts.AutoTimestamp = false;
opts.ApiCredentials = new ApiCredentials("123", "456");
});
var tester = new RestRequestValidator<BitfinexRestClient>(client, "Endpoints/Spot/ExchangeData", "https://api.bitfinex.com", IsAuthenticated, stjCompare: false);
await tester.ValidateAsync(client => client.SpotApi.ExchangeData.GetTickersAsync(), "GetTickers");
await tester.ValidateAsync(client => client.SpotApi.ExchangeData.GetPlatformStatusAsync(), "GetPlatformStatus");
}

private bool IsAuthenticated(WebCallResult result)
{
return result.RequestUrl.Contains("bfx-signature");
}
}
}
4 changes: 2 additions & 2 deletions Bitfinex.Net/Bitfinex.Net.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<Nullable>enable</Nullable>
Expand Down Expand Up @@ -51,10 +51,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="7.5.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="7.4.0" />
</ItemGroup>
</Project>
14 changes: 5 additions & 9 deletions Bitfinex.Net/BitfinexAuthenticationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,18 @@ public BitfinexAuthenticationProvider(ApiCredentials credentials, INonceProvider
_nonceProvider = nonceProvider ?? new BitfinexNonceProvider();
}

public override void AuthenticateRequest(RestApiClient apiClient, Uri uri, HttpMethod method, Dictionary<string, object> providedParameters, bool auth, ArrayParametersSerialization arraySerialization, HttpMethodParameterPosition parameterPosition, RequestBodyFormat bodyFormat, out SortedDictionary<string, object> uriParameters, out SortedDictionary<string, object> bodyParameters, out Dictionary<string, string> headers)
public override void AuthenticateRequest(RestApiClient apiClient, Uri uri, HttpMethod method, IDictionary<string, object> uriParams, IDictionary<string, object> bodyParams, Dictionary<string, string> headers, bool auth, ArrayParametersSerialization arraySerialization, HttpMethodParameterPosition parameterPosition, RequestBodyFormat bodyFormat)
{
uriParameters = parameterPosition == HttpMethodParameterPosition.InUri ? new SortedDictionary<string, object>(providedParameters) : new SortedDictionary<string, object>();
bodyParameters = parameterPosition == HttpMethodParameterPosition.InBody ? new SortedDictionary<string, object>(providedParameters) : new SortedDictionary<string, object>();
headers = new Dictionary<string, string>();

if (!auth)
return;

// Auth requests are always POST
if (uri.AbsolutePath.Contains("v1"))
{
bodyParameters.Add("request", uri.AbsolutePath);
bodyParameters.Add("nonce", _nonceProvider.GetNonce().ToString());
bodyParams.Add("request", uri.AbsolutePath);
bodyParams.Add("nonce", _nonceProvider.GetNonce().ToString());

var signature = JsonConvert.SerializeObject(bodyParameters);
var signature = JsonConvert.SerializeObject(bodyParams);
var payload = Convert.ToBase64String(Encoding.ASCII.GetBytes(signature));
var signedData = Sign(payload);

Expand All @@ -53,7 +49,7 @@ public override void AuthenticateRequest(RestApiClient apiClient, Uri uri, HttpM
}
else if (uri.AbsolutePath.Contains("v2"))
{
var json = JsonConvert.SerializeObject(bodyParameters);
var json = JsonConvert.SerializeObject(bodyParams);
var n = _nonceProvider.GetNonce().ToString();
var signature = $"/api{uri.AbsolutePath}{n}{json}";
var signedData = SignHMACSHA384(signature);
Expand Down

0 comments on commit ac20525

Please sign in to comment.