From 8419af278d17aeeb8017ad256faf1e2a9ebc200f Mon Sep 17 00:00:00 2001 From: Jkorf Date: Fri, 11 Sep 2026 13:22:48 +0200 Subject: [PATCH] wip --- .../SharedApiClientTests.cs | 153 +++++++++++++++++- CryptoExchange.Net/ExtensionMethods.cs | 95 +++++++++-- .../SharedCapabilityResolution.cs | 10 ++ .../SharedApis/Enums/SharedTransport.cs | 6 +- .../SharedApis/Models/SharedApiClientInfo.cs | 49 ++++++ .../SharedApis/Models/SharedClientInfo.cs | 10 ++ .../SharedApis/Options/SharedApiOptions.cs | 22 +++ .../Parameters/ParameterDescription.cs | 6 +- .../SharedApis/SharedApiClientBase.cs | 91 +++++++++-- .../SharedApis/SharedApiRegistrationInfo.cs | 18 +++ CryptoExchange.Net/SharedApis/SharedUtils.cs | 2 + 11 files changed, 431 insertions(+), 31 deletions(-) create mode 100644 CryptoExchange.Net/SharedApis/Models/SharedApiClientInfo.cs create mode 100644 CryptoExchange.Net/SharedApis/Options/SharedApiOptions.cs create mode 100644 CryptoExchange.Net/SharedApis/SharedApiRegistrationInfo.cs diff --git a/CryptoExchange.Net.UnitTests/SharedApiClientTests.cs b/CryptoExchange.Net.UnitTests/SharedApiClientTests.cs index 30fb4aab..e1b48287 100644 --- a/CryptoExchange.Net.UnitTests/SharedApiClientTests.cs +++ b/CryptoExchange.Net.UnitTests/SharedApiClientTests.cs @@ -1,5 +1,7 @@ -using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.SharedApis; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; +using System.Linq; namespace CryptoExchange.Net.UnitTests { @@ -16,7 +18,7 @@ namespace CryptoExchange.Net.UnitTests Assert.Multiple(() => { - Assert.That(client.GetCapability(TradingMode.Spot), Is.SameAs(sharedApi)); + Assert.That(client.GetCapability(TradingMode.Spot)?.Capability, Is.SameAs(sharedApi)); Assert.That(client.GetCapability(TradingMode.PerpetualLinear), Is.Null); Assert.That(client.GetCapabilities(TradingMode.Spot), Has.Count.EqualTo(1)); Assert.That(client.GetCapabilities(TradingMode.PerpetualLinear), Is.Empty); @@ -33,8 +35,73 @@ namespace CryptoExchange.Net.UnitTests Assert.Multiple(() => { - Assert.That(client.GetCapability(TradingMode.Spot), Is.SameAs(sharedApi)); - Assert.That(client.GetCapability(TradingMode.PerpetualLinear), Is.SameAs(sharedApi)); + Assert.That(client.GetCapability(TradingMode.Spot)?.Capability, Is.SameAs(sharedApi)); + Assert.That(client.GetCapability(TradingMode.PerpetualLinear)?.Capability, Is.SameAs(sharedApi)); + }); + } + + [Test] + public void GetCapabilities_WithReference_ShouldReturnMatchingCapabilities() + { + var sharedApi = new TestSharedApi( + [TradingMode.Spot], + [TradingMode.Spot]); + var client = new TestSharedApiClient(sharedApi); + + var result = client.GetCapabilities( + new SharedCapabilityReference(), + TradingMode.Spot); + + Assert.That(result, Has.Count.EqualTo(1)); + Assert.That(result[0].Capability, Is.SameAs(sharedApi)); + Assert.That(result[0].Options, Is.SameAs(sharedApi.CapabilityOptions)); + } + + [Test] + public void Discover_ShouldReturnAllSharedApiInformation() + { + var restApi = new TestRestSharedApi(); + var socketApi = new TestSocketSharedApi(); + var client = new TestDiSharedApiClient( + SharedTransport.Socket, + restApi, + socketApi); + + var result = client.Discover(); + + Assert.Multiple(() => + { + Assert.That(result.PreferredTransport, Is.EqualTo(SharedTransport.Socket)); + Assert.That(result.SharedApis, Has.Length.EqualTo(2)); + Assert.That(result.SharedApis[0].Transport, Is.EqualTo(SharedTransport.Rest)); + Assert.That(result.SharedApis[1].Transport, Is.EqualTo(SharedTransport.Socket)); + Assert.That(result.SharedApis[0].SupportedTradingModes, Is.EqualTo(new[] { TradingMode.Spot })); + Assert.That(result.SharedApis[0].Capabilities, Has.Length.EqualTo(1)); + Assert.That(result.SharedApis[0].Authenticated, Is.False); + }); + } + + [Test] + public void RegisterSharedApiClientCapabilities_ShouldResolvePreferredTransport() + { + var restApi = new TestRestSharedApi(); + var socketApi = new TestSocketSharedApi(); + var services = new ServiceCollection(); + + services.RegisterSharedApi(_ => restApi); + services.RegisterSharedApi(_ => socketApi); + services.AddTransient(_ => + new TestDiSharedApiClient(SharedTransport.Socket, restApi, socketApi)); + services.RegisterSharedApiClientCapabilities(); + + using var provider = services.BuildServiceProvider(); + + Assert.Multiple(() => + { + Assert.That(provider.GetRequiredService(), Is.SameAs(socketApi)); + Assert.That(provider.GetServices().ToArray(), Is.EqualTo(new[] { socketApi })); + Assert.That(provider.GetRequiredService(), Is.SameAs(restApi)); + Assert.That(provider.GetRequiredService(), Is.SameAs(socketApi)); }); } @@ -101,6 +168,28 @@ namespace CryptoExchange.Net.UnitTests { } + private interface ITestRestCapability : ITestCapability, ISharedRest + { + } + + private interface ITestSocketCapability : ITestCapability, ISharedSocket + { + } + + private interface ITestRestSharedApi : ITestRestCapability + { + } + + private interface ITestSocketSharedApi : ITestSocketCapability + { + } + + private interface ITestSharedApiClient : ISharedApiClientBase + { + ITestRestSharedApi Rest { get; } + ITestSocketSharedApi Socket { get; } + } + private sealed class TestCapabilityOptions : CapabilityOptions { public override string Description => "Test capability"; @@ -159,10 +248,64 @@ namespace CryptoExchange.Net.UnitTests public override SharedClientInfo Discover() => new(); } + private abstract class TestTransportSharedApi : SharedApiBase + { + protected TestTransportSharedApi(SharedTransport transport) + : base( + transport, + "TestExchange", + [TradingMode.Spot], + () => false, + (baseAsset, quoteAsset, tradingMode, deliverDate) => $"{baseAsset}{quoteAsset}") + { + SetCapabilities(new TestCapabilityOptions([TradingMode.Spot])); + } + + public override SharedClientInfo Discover() => new() + { + Exchange = this.Exchange, + TypeName = GetType().Name, + SupportedTradingModes = this.SupportedTradingModes, + Transport = this.Transport, + Authenticated = this.Authenticated, + Capabilities = ((ISharedApi)this).Capabilities.ToArray() + }; + } + + private sealed class TestRestSharedApi : TestTransportSharedApi, ITestRestSharedApi + { + public TestRestSharedApi() : base(SharedTransport.Rest) + { + } + } + + private sealed class TestSocketSharedApi : TestTransportSharedApi, ITestSocketSharedApi + { + public TestSocketSharedApi() : base(SharedTransport.Socket) + { + } + } + + private sealed class TestDiSharedApiClient : SharedApiClientBase, ITestSharedApiClient + { + public ITestRestSharedApi Rest { get; } + public ITestSocketSharedApi Socket { get; } + + public TestDiSharedApiClient( + SharedTransport preferredTransport, + ITestRestSharedApi rest, + ITestSocketSharedApi socket) + : base(preferredTransport, rest, socket) + { + Rest = rest; + Socket = socket; + } + } + private sealed class TestSharedApiClient : SharedApiClientBase { public TestSharedApiClient(params ISharedApiCapability[] sharedApis) - : base([SharedTransport.Rest, SharedTransport.Socket], sharedApis) + : base(SharedTransport.Rest, sharedApis) { } } diff --git a/CryptoExchange.Net/ExtensionMethods.cs b/CryptoExchange.Net/ExtensionMethods.cs index 857a0f94..8f2ccf1f 100644 --- a/CryptoExchange.Net/ExtensionMethods.cs +++ b/CryptoExchange.Net/ExtensionMethods.cs @@ -488,19 +488,77 @@ namespace CryptoExchange.Net { services.AddTransient(factory); - var markerInterfaces = new[] - { - typeof(ISharedApiCapability), - typeof(ISharedRest), - typeof(ISharedSocket), - typeof(ISharedSubscription) - }; + var allInterfaces = typeof(TSharedApi).GetInterfaces(); - var capabilityInterfaces = typeof(TSharedApi) - .GetInterfaces() + var transportCapabilityInterfaces = allInterfaces .Where(x => typeof(ISharedApiCapability).IsAssignableFrom(x) - && !markerInterfaces.Contains(x)) + && (typeof(ISharedRest).IsAssignableFrom(x) + || typeof(ISharedSocket).IsAssignableFrom(x)) + && x != typeof(ISharedRest) + && x != typeof(ISharedSocket) + && x != typeof(ISharedSubscription)) + .Distinct() + .ToArray(); + + var baseCapabilityInterfaces = allInterfaces + .Where(x => + x != typeof(ISharedApiCapability) + && typeof(ISharedApiCapability).IsAssignableFrom(x) + && !typeof(ISharedRest).IsAssignableFrom(x) + && !typeof(ISharedSocket).IsAssignableFrom(x)) + .Distinct() + .ToArray(); + + services.AddSingleton(new SharedApiRegistrationInfo( + typeof(TSharedApi), + baseCapabilityInterfaces)); + + foreach (var capabilityInterface in transportCapabilityInterfaces) + { + services.AddTransient( + capabilityInterface, + serviceProvider => + serviceProvider.GetRequiredService()); + } + + return services; + } + + /// + /// Registers transport-agnostic Shared API capabilities through the + /// exchange-specific Shared API aggregate client. + /// + public static IServiceCollection RegisterSharedApiClientCapabilities< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicConstructors)] +#endif + TSharedApiClient>( + this IServiceCollection services) + where TSharedApiClient : class, ISharedApiClientBase + { + services.AddTransient(serviceProvider => + serviceProvider.GetRequiredService()); + + var sharedApiTypes = new HashSet( + typeof(TSharedApiClient) + .GetProperties() + .Where(property => + typeof(ISharedApi).IsAssignableFrom( + property.PropertyType)) + .Select(property => property.PropertyType)); + + var capabilityInterfaces = services + .Where(descriptor => + descriptor.ImplementationInstance + is SharedApiRegistrationInfo) + .Select(descriptor => + (SharedApiRegistrationInfo)descriptor.ImplementationInstance!) + .Where(registration => + sharedApiTypes.Contains(registration.SharedApiType)) + .SelectMany(registration => + registration.BaseCapabilityTypes) .Distinct() .ToArray(); @@ -509,7 +567,22 @@ namespace CryptoExchange.Net services.AddTransient( capabilityInterface, serviceProvider => - serviceProvider.GetRequiredService()); + { + var sharedApiClient = serviceProvider + .GetRequiredService(); + + if (sharedApiClient is not ISharedApiClientResolver resolver) + { + throw new InvalidOperationException( + $"{typeof(TSharedApiClient).Name} should derive from " + + $"{nameof(SharedApiClientBase)}"); + } + + return resolver.GetCapability(capabilityInterface) + ?? throw new InvalidOperationException( + $"No implementation of " + + $"{capabilityInterface.Name} is available"); + }); } return services; diff --git a/CryptoExchange.Net/SharedApis/CapabilityReferences/SharedCapabilityResolution.cs b/CryptoExchange.Net/SharedApis/CapabilityReferences/SharedCapabilityResolution.cs index 5ac99b05..c51ca506 100644 --- a/CryptoExchange.Net/SharedApis/CapabilityReferences/SharedCapabilityResolution.cs +++ b/CryptoExchange.Net/SharedApis/CapabilityReferences/SharedCapabilityResolution.cs @@ -11,6 +11,16 @@ namespace CryptoExchange.Net.SharedApis public class SharedCapabilityResolution where T : ISharedApiCapability { + /// + /// The exchange name + /// + public string Exchange => Capability.Exchange; + + /// + /// The transport type + /// + public SharedTransport Transport => Capability.Transport; + /// /// The capability /// diff --git a/CryptoExchange.Net/SharedApis/Enums/SharedTransport.cs b/CryptoExchange.Net/SharedApis/Enums/SharedTransport.cs index ca408b20..869c58a7 100644 --- a/CryptoExchange.Net/SharedApis/Enums/SharedTransport.cs +++ b/CryptoExchange.Net/SharedApis/Enums/SharedTransport.cs @@ -7,15 +7,15 @@ namespace CryptoExchange.Net.SharedApis /// /// The type of transport used for the shared API /// - public record SharedTransport(string Name) + public enum SharedTransport { /// /// REST transport /// - public static SharedTransport Rest { get; } = new("REST"); + Rest, /// /// WebSocket transport /// - public static SharedTransport Socket { get; } = new("WebSocket"); + Socket } } diff --git a/CryptoExchange.Net/SharedApis/Models/SharedApiClientInfo.cs b/CryptoExchange.Net/SharedApis/Models/SharedApiClientInfo.cs new file mode 100644 index 00000000..ddbbcf08 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Models/SharedApiClientInfo.cs @@ -0,0 +1,49 @@ +using System.Text; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Discovery information for a Shared API client. + /// + public class SharedApiClientInfo + { + /// + /// Preferred transport when multiple implementations of a capability are available. + /// + public SharedTransport PreferredTransport { get; } + + /// + /// Shared APIs available on the client. + /// + public SharedClientInfo[] SharedApis { get; } + + internal SharedApiClientInfo( + SharedTransport preferredTransport, + SharedClientInfo[] sharedApis) + { + PreferredTransport = preferredTransport; + SharedApis = sharedApis; + } + + /// + public override string ToString() => ToString(false); + + /// + /// Create a string representation of the available Shared APIs. + /// + /// Whether to include detailed capability information. + public string ToString(bool detailed) + { + var builder = new StringBuilder(); + builder.AppendLine($"Preferred transport: {PreferredTransport}"); + + foreach (var sharedApi in SharedApis) + { + builder.AppendLine(); + builder.Append(sharedApi.ToString(detailed)); + } + + return builder.ToString(); + } + } +} diff --git a/CryptoExchange.Net/SharedApis/Models/SharedClientInfo.cs b/CryptoExchange.Net/SharedApis/Models/SharedClientInfo.cs index 3c27f6a6..a00dd347 100644 --- a/CryptoExchange.Net/SharedApis/Models/SharedClientInfo.cs +++ b/CryptoExchange.Net/SharedApis/Models/SharedClientInfo.cs @@ -35,6 +35,14 @@ namespace CryptoExchange.Net.SharedApis /// public CentralizationType CentralizationType { get; set; } /// + /// The underlying transport type used by this client + /// + public SharedTransport Transport { get; init; } + /// + /// Whether API credentials have been configured for this client. Does not check whether the credentials are valid. + /// + public bool Authenticated { get; init; } + /// /// Use Capabilities instead /// #pragma warning disable CS0618 // Type or member is obsolete @@ -74,6 +82,8 @@ namespace CryptoExchange.Net.SharedApis sb.AppendLine($"Supported environments: {string.Join(", ", SupportedEnvironments)}"); sb.AppendLine($"Supported trading modes: {string.Join(", ", SupportedTradingModes)}"); sb.AppendLine($"Centralization type: {CentralizationType}"); + sb.AppendLine($"Transport: {Transport}"); + sb.AppendLine($"Authenticated: {Authenticated}"); sb.AppendLine($"Capabilities:"); foreach (var capability in Capabilities) { diff --git a/CryptoExchange.Net/SharedApis/Options/SharedApiOptions.cs b/CryptoExchange.Net/SharedApis/Options/SharedApiOptions.cs new file mode 100644 index 00000000..582135a4 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Options/SharedApiOptions.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Options for Shared API client instances + /// + public class SharedApiOptions + { + /// + /// Whether to use XPerps as perpetual linear contracts when using the Shared API's + /// + public bool EuropeUseXPerps { get; set; } + /// + /// The preferred transport type when requesting transport agnostic capabilities + /// + public SharedTransport PreferredTransport { get; set; } + = SharedTransport.Rest; + } +} diff --git a/CryptoExchange.Net/SharedApis/Parameters/ParameterDescription.cs b/CryptoExchange.Net/SharedApis/Parameters/ParameterDescription.cs index b2a0088c..3dafef1b 100644 --- a/CryptoExchange.Net/SharedApis/Parameters/ParameterDescription.cs +++ b/CryptoExchange.Net/SharedApis/Parameters/ParameterDescription.cs @@ -65,7 +65,7 @@ namespace CryptoExchange.Net.SharedApis /// public override string ToString() { - return $"[{ValueType.Name}] \"{Name}\" {string.Join(" / ", Aliases.Select(x => $"\"{x}\""))}: {Description}"; + return $"[{(Nullable.GetUnderlyingType(ValueType) ?? ValueType).Name}] \"{Name}\" {string.Join(" / ", Aliases.Select(x => $"\"{x}\""))}: {Description}"; } } @@ -135,7 +135,7 @@ namespace CryptoExchange.Net.SharedApis /// public override string ToString() { - return $"[{Support}] [{ValueType.Name}] \"{Name}\" {string.Join(" / ", Aliases.Select(x => $"\"{x}\""))}: {Description}"; + return $"[{Support}] [{(Nullable.GetUnderlyingType(ValueType) ?? ValueType).Name}] \"{Name}\" {string.Join(" / ", Aliases.Select(x => $"\"{x}\""))}: {Description}"; } } @@ -167,7 +167,7 @@ namespace CryptoExchange.Net.SharedApis /// public override string ToString() { - return $"[{Requirement}] [{ValueType.Name}] \"{Name}\" {string.Join(" / ", Aliases.Select(x => $"\"{x}\""))}: {Description}"; + return $"[{Requirement}] [{(Nullable.GetUnderlyingType(ValueType) ?? ValueType).Name}] \"{Name}\" {string.Join(" / ", Aliases.Select(x => $"\"{x}\""))}: {Description}"; } } } diff --git a/CryptoExchange.Net/SharedApis/SharedApiClientBase.cs b/CryptoExchange.Net/SharedApis/SharedApiClientBase.cs index 6c3e101c..09f83740 100644 --- a/CryptoExchange.Net/SharedApis/SharedApiClientBase.cs +++ b/CryptoExchange.Net/SharedApis/SharedApiClientBase.cs @@ -1,10 +1,15 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CryptoExchange.Net.SharedApis { + internal interface ISharedApiClientResolver + { + object? GetCapability(Type capabilityType); + } + /// /// Base interface for Shared API clients /// @@ -14,6 +19,19 @@ namespace CryptoExchange.Net.SharedApis /// Shared API's available on this client /// IReadOnlyList SharedApis { get; } + /// + /// Preferred transport selection when multiple transport options are available + /// + SharedTransport PreferredTransport { get; } + + /// + /// Get discovery information for the Shared APIs available on this client. + /// + SharedApiClientInfo Discover(); + /// + /// The exchange name of this client + /// + string Exchange { get; } /// /// Get all capabilities matching the provided capability type. @@ -26,6 +44,17 @@ namespace CryptoExchange.Net.SharedApis IReadOnlyList> GetCapabilities(TradingMode? tradingMode = null, SharedTransport? transport = null) where T : ISharedApiCapability; + /// + /// Get all capabilities matching the provided capability reference. + /// + /// The capability type. + /// The capability reference. + /// Filter by supported trading mode. + IReadOnlyList> GetCapabilities( + SharedCapabilityReference capability, + TradingMode? tradingMode = null) + where T : ISharedApiCapability; + /// /// Get the requested capability type. If more than one implementation is available the first one is returned. /// In this case prefer using to select a specific trading mode. @@ -74,30 +103,43 @@ namespace CryptoExchange.Net.SharedApis /// The requested capability type or null if not found SharedCapabilityResolution? GetCapability(SharedCapabilityReference capability, TradingMode tradingMode) where T : ISharedApiCapability; + } /// /// Base client for Shared API clients /// - public abstract class SharedApiClientBase : ISharedApiClientBase + public abstract class SharedApiClientBase : ISharedApiClientBase, ISharedApiClientResolver { private readonly ISharedApi[] _sharedApis; - private readonly SharedTransport[] _preferredTransports; + private readonly SharedTransport _preferredTransport; /// public IReadOnlyList SharedApis => _sharedApis; + /// + public SharedTransport PreferredTransport => _preferredTransport; + /// + public string Exchange => _sharedApis[0].Exchange; /// /// ctor /// public SharedApiClientBase( - IEnumerable transportPreference, + SharedTransport transportPreference, params ISharedApi[] sharedApis) { - _preferredTransports = transportPreference.Distinct().ToArray(); + _preferredTransport = transportPreference; _sharedApis = sharedApis.Distinct().ToArray(); } + /// + public SharedApiClientInfo Discover() + { + return new SharedApiClientInfo( + PreferredTransport, + _sharedApis.Select(x => x.Discover()).ToArray()); + } + /// public SharedCapabilityResolution? GetCapability(SharedTransport? transport = null) where T : ISharedApiCapability @@ -126,6 +168,7 @@ namespace CryptoExchange.Net.SharedApis return GetCapabilityCore(tradingMode, null); } + /// public IReadOnlyList> GetCapabilities( TradingMode? tradingMode = null, @@ -157,6 +200,29 @@ namespace CryptoExchange.Net.SharedApis .ToArray(); } + /// + public IReadOnlyList> GetCapabilities( + SharedCapabilityReference capability, + TradingMode? tradingMode = null) + where T : ISharedApiCapability + { + return GetCapabilities(tradingMode); + } + + object? ISharedApiClientResolver.GetCapability(Type capabilityType) + { + return _sharedApis + .Where(sharedApi => + capabilityType.IsInstanceOfType(sharedApi) + && GetMatchingOptions( + sharedApi, + capabilityType, + null) != null) + .OrderBy(sharedApi => + GetTransportPriority(sharedApi.Transport)) + .FirstOrDefault(); + } + private SharedCapabilityResolution? GetCapabilityCore( TradingMode? tradingMode, SharedTransport? selectedTransport = null) @@ -171,8 +237,17 @@ namespace CryptoExchange.Net.SharedApis TradingMode? tradingMode) where T : ISharedApiCapability { - var requestedType = typeof(T); + return GetMatchingOptions( + sharedApi, + typeof(T), + tradingMode); + } + private static CapabilityOptions? GetMatchingOptions( + ISharedApi sharedApi, + Type requestedType, + TradingMode? tradingMode) + { return sharedApi.Capabilities .Where(options => options.Supported @@ -182,7 +257,6 @@ namespace CryptoExchange.Net.SharedApis && (tradingMode == null || options.SupportedTradingModes.Contains( tradingMode.Value))) - // Prefer options declared for the exact requested interface. .OrderByDescending(options => options.CapabilityType == requestedType) .FirstOrDefault(); @@ -198,8 +272,7 @@ namespace CryptoExchange.Net.SharedApis private int GetTransportPriority(SharedTransport transport) { - var index = Array.IndexOf(_preferredTransports, transport); - return index == -1 ? int.MaxValue : index; + return transport == _preferredTransport ? 0 : 1; } } } diff --git a/CryptoExchange.Net/SharedApis/SharedApiRegistrationInfo.cs b/CryptoExchange.Net/SharedApis/SharedApiRegistrationInfo.cs new file mode 100644 index 00000000..83a2a78d --- /dev/null +++ b/CryptoExchange.Net/SharedApis/SharedApiRegistrationInfo.cs @@ -0,0 +1,18 @@ +using System; + +namespace CryptoExchange.Net.SharedApis +{ + internal sealed class SharedApiRegistrationInfo + { + public Type SharedApiType { get; } + public Type[] BaseCapabilityTypes { get; } + + public SharedApiRegistrationInfo( + Type sharedApiType, + Type[] baseCapabilityTypes) + { + SharedApiType = sharedApiType; + BaseCapabilityTypes = baseCapabilityTypes; + } + } +} diff --git a/CryptoExchange.Net/SharedApis/SharedUtils.cs b/CryptoExchange.Net/SharedApis/SharedUtils.cs index 6c5c5f5f..dce2897c 100644 --- a/CryptoExchange.Net/SharedApis/SharedUtils.cs +++ b/CryptoExchange.Net/SharedApis/SharedUtils.cs @@ -21,6 +21,8 @@ namespace CryptoExchange.Net.SharedApis SupportedEnvironments = platformInfo.SupportedEnvironments, SupportedTradingModes = client.SupportedTradingModes, CentralizationType = platformInfo.CentralizationType, + Transport = client.Transport, + Authenticated = client.Authenticated, Capabilities = client.Capabilities.Where(x => x.Supported).ToArray() }; }