diff --git a/Source/Builder/App.config b/Source/Builder/App.config new file mode 100644 index 0000000..adcd8c5 --- /dev/null +++ b/Source/Builder/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Source/Builder/Builder.fsproj b/Source/Builder/Builder.fsproj index 84159af..d18b820 100644 --- a/Source/Builder/Builder.fsproj +++ b/Source/Builder/Builder.fsproj @@ -2,6 +2,7 @@ + 4.6 Debug AnyCPU 2.0 @@ -9,10 +10,11 @@ Exe Builder2 Builder2 - v4.5 + v4.6.2 true 4.4.0.0 Builder + true @@ -56,12 +58,17 @@ + + Always + + - - + + ..\packages\FSharp.Core.4.0.0.1\lib\net40\FSharp.Core.dll True + diff --git a/Source/Builder/build.fsx b/Source/Builder/build.fsx index b4bd54e..45968cb 100644 --- a/Source/Builder/build.fsx +++ b/Source/Builder/build.fsx @@ -22,8 +22,8 @@ nuget Fake.Tools.Git nuget Fake.DotNet.Testing.xUnit2 nuget Fake.BuildServer.AppVeyor -nuget SharpCompress = 0.22.0 -nuget FSharp.Data = 2.4.6 +nuget SharpCompress = 0.35.0 +nuget FSharp.Data = 6.3.0 nuget secure-file = 1.0.31 diff --git a/Source/Builder/build.fsx.lock b/Source/Builder/build.fsx.lock deleted file mode 100644 index 15d93bc..0000000 --- a/Source/Builder/build.fsx.lock +++ /dev/null @@ -1,748 +0,0 @@ -STORAGE: NONE -RESTRICTION: == netstandard2.0 -NUGET - remote: https://api.nuget.org/v3/index.json - BlackFox.VsWhere (1.1) - FSharp.Core (>= 4.2.3) - Microsoft.Win32.Registry (>= 4.7) - Chessie (0.6) - FSharp.Core (>= 4.0.1.7-alpha) - NETStandard.Library (>= 1.6) - Fake.BuildServer.AppVeyor (5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.Process (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - Fake.Net.Http (>= 5.20.4) - FSharp.Core (>= 4.7.2) - FAKE.Core (5.16) - Fake.Core.CommandLineParsing (5.20.4) - FParsec (>= 1.1.1) - FSharp.Core (>= 4.7.2) - Fake.Core.Context (5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.DependencyManager.Paket (5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.Environment (5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.FakeVar (5.20.4) - Fake.Core.Context (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.Process (5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.FakeVar (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - FSharp.Core (>= 4.7.2) - System.Collections.Immutable (>= 1.7.1) - Fake.Core.SemVer (5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.String (5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.Target (5.20.4) - Fake.Core.CommandLineParsing (>= 5.20.4) - Fake.Core.Context (>= 5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.FakeVar (>= 5.20.4) - Fake.Core.Process (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - FSharp.Control.Reactive (>= 4.4.2) - FSharp.Core (>= 4.7.2) - Fake.Core.Tasks (5.20.4) - Fake.Core.Trace (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.Trace (5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.FakeVar (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Core.Xml (5.20.4) - Fake.Core.String (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.DotNet.AssemblyInfoFile (5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.DotNet.Cli (5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.Process (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.DotNet.MSBuild (>= 5.20.4) - Fake.DotNet.NuGet (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Mono.Posix.NETStandard (>= 1.0) - Newtonsoft.Json (>= 12.0.3) - Fake.DotNet.MSBuild (5.20.4) - BlackFox.VsWhere (>= 1.1) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.Process (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - FSharp.Core (>= 4.7.2) - MSBuild.StructuredLogger (>= 2.1.176) - Fake.DotNet.NuGet (5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.Process (>= 5.20.4) - Fake.Core.SemVer (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Tasks (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.Core.Xml (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - Fake.Net.Http (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Newtonsoft.Json (>= 12.0.3) - NuGet.Protocol (>= 5.6) - Fake.DotNet.Testing.XUnit2 (5.20.4) - Fake.Core.Process (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - Fake.Testing.Common (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.IO.FileSystem (5.20.4) - Fake.Core.String (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.IO.Zip (5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Net.Http (5.20.4) - Fake.Core.Trace (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Runtime (5.20.4) - Fake.Core.Context (>= 5.20.4) - Fake.Core.DependencyManager.Paket (>= 5.20.4) - FSharp.Compiler.Service (>= 37.0) - FSharp.Core (>= 5.0) - Microsoft.DotNet.PlatformAbstractions (>= 2.1) - Mono.Cecil (>= 0.11.3) - Paket.Core (>= 5.257) - System.Runtime.Loader (>= 4.3) - Fake.Testing.Common (5.20.4) - Fake.Core.Trace (>= 5.20.4) - FSharp.Core (>= 4.7.2) - Fake.Tools.Git (5.20.4) - Fake.Core.Environment (>= 5.20.4) - Fake.Core.Process (>= 5.20.4) - Fake.Core.SemVer (>= 5.20.4) - Fake.Core.String (>= 5.20.4) - Fake.Core.Trace (>= 5.20.4) - Fake.IO.FileSystem (>= 5.20.4) - FSharp.Core (>= 4.7.2) - FParsec (1.1.1) - FSharp.Core (>= 4.3.4) - FSharp.Compiler.Service (41.0.1) - FSharp.Core (6.0.1) - Microsoft.Build.Framework (>= 16.11) - Microsoft.Build.Tasks.Core (>= 16.11) - Microsoft.Build.Utilities.Core (>= 16.11) - System.Buffers (>= 4.5.1) - System.Collections.Immutable (>= 5.0) - System.Diagnostics.Process (>= 4.3) - System.Diagnostics.TraceSource (>= 4.3) - System.Linq.Expressions (>= 4.3) - System.Linq.Queryable (>= 4.3) - System.Memory (>= 4.5.4) - System.Net.Requests (>= 4.3) - System.Net.Security (>= 4.3.1) - System.Reflection.Emit (>= 4.3) - System.Reflection.Metadata (>= 5.0) - System.Reflection.TypeExtensions (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.CompilerServices.Unsafe (>= 5.0) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Loader (>= 4.3) - System.Security.Claims (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Principal (>= 4.3) - System.Threading.Tasks.Parallel (>= 4.3) - System.Threading.Thread (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - FSharp.Control.Reactive (5.0.2) - FSharp.Core (>= 4.7.2) - System.Reactive (>= 5.0) - FSharp.Core (6.0.1) - FSharp.Data (2.4.6) - Zlib.Portable (>= 1.11) - Microsoft.Build (17.0) - Microsoft.Build.Framework (17.0) - System.Security.Permissions (>= 4.7) - Microsoft.Build.Tasks.Core (17.0) - Microsoft.Build.Framework (>= 17.0) - Microsoft.Build.Utilities.Core (>= 17.0) - Microsoft.NET.StringTools (>= 1.0) - Microsoft.Win32.Registry (>= 4.3) - System.CodeDom (>= 4.4) - System.Collections.Immutable (>= 5.0) - System.Reflection.Metadata (>= 1.6) - System.Resources.Extensions (>= 4.6) - System.Security.Cryptography.Pkcs (>= 4.7) - System.Security.Cryptography.Xml (>= 4.7) - System.Security.Permissions (>= 4.7) - System.Threading.Tasks.Dataflow (>= 4.9) - Microsoft.Build.Utilities.Core (17.0) - Microsoft.Build.Framework (>= 17.0) - Microsoft.NET.StringTools (>= 1.0) - Microsoft.Win32.Registry (>= 4.3) - System.Collections.Immutable (>= 5.0) - System.Configuration.ConfigurationManager (>= 4.7) - System.Security.Permissions (>= 4.7) - System.Text.Encoding.CodePages (>= 4.0.1) - Microsoft.CSharp (4.7) - Microsoft.DotNet.PlatformAbstractions (3.1.6) - Microsoft.NET.StringTools (1.0) - System.Memory (>= 4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 5.0) - Microsoft.NETCore.Platforms (6.0) - Microsoft.NETCore.Targets (5.0) - Microsoft.Win32.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - Microsoft.Win32.Registry (5.0) - System.Buffers (>= 4.5.1) - System.Memory (>= 4.5.4) - System.Security.AccessControl (>= 5.0) - System.Security.Principal.Windows (>= 5.0) - Mono.Cecil (0.11.4) - Mono.Posix.NETStandard (1.0) - MSBuild.StructuredLogger (2.1.545) - Microsoft.Build (>= 16.10) - Microsoft.Build.Framework (>= 16.10) - Microsoft.Build.Tasks.Core (>= 16.10) - Microsoft.Build.Utilities.Core (>= 16.10) - NETStandard.Library (2.0.3) - Microsoft.NETCore.Platforms (>= 1.1) - Newtonsoft.Json (13.0.1) - NuGet.Common (6.0) - NuGet.Frameworks (>= 6.0) - NuGet.Configuration (6.0) - NuGet.Common (>= 6.0) - System.Security.Cryptography.ProtectedData (>= 4.4) - NuGet.Frameworks (6.0) - NuGet.Packaging (6.0) - Newtonsoft.Json (>= 13.0.1) - NuGet.Configuration (>= 6.0) - NuGet.Versioning (>= 6.0) - System.Security.Cryptography.Cng (>= 5.0) - System.Security.Cryptography.Pkcs (>= 5.0) - NuGet.Protocol (6.0) - NuGet.Packaging (>= 6.0) - NuGet.Versioning (6.0) - Paket.Core (6.2.1) - Chessie (>= 0.6) - FSharp.Core (>= 5.0) - Mono.Cecil (>= 0.11.3) - Newtonsoft.Json (>= 13.0.1) - NuGet.Packaging (>= 5.9.1) - System.Net.Http (>= 4.3.4) - System.Net.Http.WinHttpHandler (>= 5.0) - System.Security.Cryptography.ProtectedData (>= 5.0) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.native.System (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Data.SqlClient.sni (4.7) - runtime.win-arm64.runtime.native.System.Data.SqlClient.sni (>= 4.4) - runtime.win-x64.runtime.native.System.Data.SqlClient.sni (>= 4.4) - runtime.win-x86.runtime.native.System.Data.SqlClient.sni (>= 4.4) - runtime.native.System.Net.Http (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Net.Security (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.win-arm64.runtime.native.System.Data.SqlClient.sni (4.4) - runtime.win-x64.runtime.native.System.Data.SqlClient.sni (4.4) - runtime.win-x86.runtime.native.System.Data.SqlClient.sni (4.4) - secure-file (1.0.31) - SharpCompress (0.22) - System.Text.Encoding.CodePages (>= 4.5) - System.Buffers (4.5.1) - System.CodeDom (6.0) - System.Collections (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Collections.Concurrent (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Collections.Immutable (6.0) - System.Memory (>= 4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Configuration.ConfigurationManager (6.0) - System.Security.Cryptography.ProtectedData (>= 6.0) - System.Security.Permissions (>= 6.0) - System.Data.SqlClient (4.8.3) - Microsoft.Win32.Registry (>= 4.7) - runtime.native.System.Data.SqlClient.sni (>= 4.7) - System.Buffers (>= 4.5.1) - System.Diagnostics.DiagnosticSource (>= 4.7) - System.Memory (>= 4.5.4) - System.Security.Principal.Windows (>= 4.7) - System.Text.Encoding.CodePages (>= 4.7) - System.Diagnostics.Debug (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Diagnostics.DiagnosticSource (6.0) - System.Memory (>= 4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Diagnostics.Process (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.Win32.Primitives (>= 4.3) - Microsoft.Win32.Registry (>= 4.3) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Text.Encoding.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Thread (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - System.Diagnostics.TraceSource (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Diagnostics.Tracing (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Formats.Asn1 (6.0) - System.Buffers (>= 4.5.1) - System.Memory (>= 4.5.4) - System.Globalization (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Globalization.Calendars (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Runtime (>= 4.3) - System.Globalization.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.IO (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem.Primitives (4.3) - System.Runtime (>= 4.3) - System.Linq (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Linq.Expressions (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Linq (>= 4.3) - System.ObjectModel (>= 4.3) - System.Reflection (>= 4.3) - System.Reflection.Emit (>= 4.3) - System.Reflection.Emit.ILGeneration (>= 4.3) - System.Reflection.Emit.Lightweight (>= 4.3) - System.Reflection.Extensions (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Reflection.TypeExtensions (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Linq.Queryable (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Linq (>= 4.3) - System.Linq.Expressions (>= 4.3) - System.Reflection (>= 4.3) - System.Reflection.Extensions (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Memory (4.5.4) - System.Buffers (>= 4.5.1) - System.Numerics.Vectors (>= 4.4) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - System.Net.Http (4.3.4) - Microsoft.NETCore.Platforms (>= 1.1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.DiagnosticSource (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Extensions (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Security.Cryptography.X509Certificates (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Net.Http.WinHttpHandler (6.0) - System.Buffers (>= 4.5.1) - System.Memory (>= 4.5.4) - System.Net.Primitives (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (>= 4.3) - System.Net.Requests (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Net.Http (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Net.WebHeaderCollection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Net.Security (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.Win32.Primitives (>= 4.3) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Security (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Extensions (>= 4.3) - System.IO (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Claims (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Security.Cryptography.X509Certificates (>= 4.3) - System.Security.Principal (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - System.Net.WebHeaderCollection (4.3) - System.Collections (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Numerics.Vectors (4.5) - System.ObjectModel (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Reactive (5.0) - System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - System.Threading.Tasks.Extensions (>= 4.5.4) - System.Reflection (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Emit (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - System.Reflection.Emit.ILGeneration (4.7) - System.Reflection.Emit.Lightweight (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - System.Reflection.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Metadata (6.0) - System.Collections.Immutable (>= 6.0) - System.Reflection.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Reflection.TypeExtensions (4.7) - System.Resources.Extensions (6.0) - System.Memory (>= 4.5.4) - System.Resources.ResourceManager (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime.Caching (6.0) - System.Configuration.ConfigurationManager (>= 6.0) - System.Runtime.CompilerServices.Unsafe (6.0) - System.Runtime.Extensions (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.InteropServices (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices.WindowsRuntime (4.3) - System.Runtime (>= 4.3) - System.Runtime.Loader (4.3) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Numerics (4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Security.AccessControl (6.0) - System.Security.Principal.Windows (>= 5.0) - System.Security.Claims (4.3) - System.Collections (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Security.Principal (>= 4.3) - System.Security.Cryptography.Algorithms (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.Cng (5.0) - System.Security.Cryptography.Csp (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Security.Cryptography.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Linq (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (5.0) - System.Security.Cryptography.Pkcs (6.0) - System.Buffers (>= 4.5.1) - System.Formats.Asn1 (>= 6.0) - System.Memory (>= 4.5.4) - System.Security.Cryptography.Cng (>= 5.0) - System.Security.Cryptography.Primitives (4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Security.Cryptography.ProtectedData (6.0) - System.Memory (>= 4.5.4) - System.Security.Cryptography.X509Certificates (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Calendars (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Cng (>= 4.3) - System.Security.Cryptography.Csp (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Security.Cryptography.Xml (6.0) - System.Memory (>= 4.5.4) - System.Security.AccessControl (>= 6.0) - System.Security.Cryptography.Pkcs (>= 6.0) - System.Security.Permissions (6.0) - System.Security.AccessControl (>= 6.0) - System.Security.Principal (4.3) - System.Runtime (>= 4.3) - System.Security.Principal.Windows (5.0) - System.Text.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding.CodePages (6.0) - System.Memory (>= 4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Text.Encoding.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (4.3) - System.Runtime (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Tasks (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Threading.Tasks.Dataflow (6.0) - System.Threading.Tasks.Extensions (4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - System.Threading.Tasks.Parallel (4.3) - System.Collections.Concurrent (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Thread (4.3) - System.Runtime (>= 4.3) - System.Threading.ThreadPool (4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - Z.ExtensionMethods.WithTwoNamespace (2.1.1) - Microsoft.CSharp (>= 4.5) - System.Data.SqlClient (>= 4.5.1) - Zlib.Portable (1.11) diff --git a/Source/Builder/packages.config b/Source/Builder/packages.config new file mode 100644 index 0000000..519df9e --- /dev/null +++ b/Source/Builder/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Source/Coinbase.Tests/Coinbase.Tests.csproj b/Source/Coinbase.Tests/Coinbase.Tests.csproj index 9a51f5b..66cf6ed 100644 --- a/Source/Coinbase.Tests/Coinbase.Tests.csproj +++ b/Source/Coinbase.Tests/Coinbase.Tests.csproj @@ -1,6 +1,6 @@ - net461;netcoreapp3.1;net6.0 + net462;net6.0 Library @@ -8,17 +8,17 @@ - - - - - - - - - + + + + + + + + + - + diff --git a/Source/Coinbase.Tests/CoinbaseApiKeyTests.cs b/Source/Coinbase.Tests/CoinbaseApiKeyTests.cs index 8c4cd91..e9ae654 100644 --- a/Source/Coinbase.Tests/CoinbaseApiKeyTests.cs +++ b/Source/Coinbase.Tests/CoinbaseApiKeyTests.cs @@ -2,23 +2,23 @@ namespace Coinbase.Tests { - [TestFixture] public class CoinbaseApiKeyTests : ServerTest { public string apiKey = "DBBD0428-B818-4F53-A5F4-F553DC4C374C"; private CoinbaseClient client; [SetUp] - public void BeforeEachTest() + public override void BeforeEachTest() { + base.BeforeEachTest(); client = new CoinbaseClient(new ApiKeyConfig{ ApiKey = "", ApiSecret = ""}); } [TearDown] - public void AfterEachTest() + public override void AfterEachTest() { EnsureEveryRequestHasCorrectHeaders(); - this.server.Dispose(); + base.AfterEachTest(); } private void EnsureEveryRequestHasCorrectHeaders() @@ -28,7 +28,5 @@ private void EnsureEveryRequestHasCorrectHeaders() .WithHeader(HeaderNames.AccessKey, apiKey) .WithHeader("User-Agent", CoinbaseClient.UserAgent); } - - } } diff --git a/Source/Coinbase.Tests/Endpoints/AccountTests.cs b/Source/Coinbase.Tests/Endpoints/AccountTests.cs index c760677..82c8ac5 100644 --- a/Source/Coinbase.Tests/Endpoints/AccountTests.cs +++ b/Source/Coinbase.Tests/Endpoints/AccountTests.cs @@ -4,18 +4,33 @@ using Coinbase.Models; using FluentAssertions; using NUnit.Framework; +using System; +using System.Configuration; using static Coinbase.Tests.Examples; namespace Coinbase.Tests.Endpoints { + [TestFixture] public class AccountTests : OAuthServerTest { [Test] - public async Task can_list_accounts() + public void can_list_accounts() { SetupServerPagedResponse(PaginationJson, $"{Account1},{Account2}"); - var accounts = await client.Accounts.ListAccountsAsync(); + PagedResponse accounts = default; + + Assert.DoesNotThrowAsync(async () => + accounts = await client.Accounts.ListAccountsAsync( + new PaginationOptions + { + Limit = 25, Order = "desc" + }) + ); + + Assert.That(accounts, Is.Not.Null); + + Assert.That(accounts.Data.Length == 2); var truth = new PagedResponse { @@ -25,10 +40,12 @@ public async Task can_list_accounts() truth.Should().BeEquivalentTo(accounts); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts") + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts") .WithVerb(HttpMethod.Get); - } + Console.WriteLine("*** UNIT TEST PASSED ***"); + } + [Test] public async Task get_an_account() { @@ -43,8 +60,10 @@ public async Task get_an_account() truth.Should().BeEquivalentTo(account); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/{Account2Model.Id}") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/accounts/{Account2Model.Id}") .WithVerb(HttpMethod.Get); + + Console.WriteLine("*** UNIT TEST PASSED ***"); } [Test] @@ -61,8 +80,10 @@ public async Task can_set_account_as_primary() truth.Should().BeEquivalentTo(account); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/{Account3Model.Id}/primary") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/accounts/{Account3Model.Id}/primary") .WithVerb(HttpMethod.Post); + + Console.WriteLine("*** UNIT TEST PASSED ***"); } [Test] @@ -81,8 +102,10 @@ public async Task can_update_account() truth.Should().BeEquivalentTo(account); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/{Account3Model.Id}") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/accounts/{Account3Model.Id}") .WithVerb(HttpMethod.Put); + + Console.WriteLine("*** UNIT TEST PASSED ***"); } [Test] @@ -93,10 +116,8 @@ public async Task can_delete_account() r.StatusCode.Should().Be((int)HttpStatusCode.NoContent); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/ffff") + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/ffff") .WithVerb(HttpMethod.Delete); } - - } } diff --git a/Source/Coinbase.Tests/Endpoints/AddressTests.cs b/Source/Coinbase.Tests/Endpoints/AddressTests.cs index e26a51e..99ff925 100644 --- a/Source/Coinbase.Tests/Endpoints/AddressTests.cs +++ b/Source/Coinbase.Tests/Endpoints/AddressTests.cs @@ -1,16 +1,16 @@ -using System.Net; -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; using Coinbase.Models; using FluentAssertions; using NUnit.Framework; +using System; using static Coinbase.Tests.Examples; namespace Coinbase.Tests.Endpoints { + [TestFixture] public class AddressTests : OAuthServerTest { - [Test] public async Task can_list_addresses() { @@ -26,8 +26,10 @@ public async Task can_list_addresses() truth.Should().BeEquivalentTo(accounts); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/ffff/addresses") + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/ffff/addresses") .WithVerb(HttpMethod.Get); + + Console.WriteLine("*** UNIT TEST PASSED ***"); } [Test] @@ -44,11 +46,11 @@ public async Task get_an_address() truth.Should().BeEquivalentTo(account); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/ffff/addresses/{Address1Model.Id}") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/accounts/ffff/addresses/{Address1Model.Id}") .WithVerb(HttpMethod.Get); - } - + Console.WriteLine("*** UNIT TEST PASSED ***"); + } [Test] public async Task can_list_address_transactions() @@ -65,8 +67,10 @@ public async Task can_list_address_transactions() truth.Should().BeEquivalentTo(txs); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/addresses/uuu/transactions") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/accounts/fff/addresses/uuu/transactions") .WithVerb(HttpMethod.Get); + + Console.WriteLine("*** UNIT TEST PASSED ***"); } [Test] @@ -86,9 +90,10 @@ public async Task can_create_address() truth.Should().BeEquivalentTo(add); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/addresses") + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/addresses") .WithVerb(HttpMethod.Post); - } + Console.WriteLine("*** UNIT TEST PASSED ***"); + } } -} \ No newline at end of file +} diff --git a/Source/Coinbase.Tests/Endpoints/ApiParameterTests.cs b/Source/Coinbase.Tests/Endpoints/ApiParameterTests.cs index 859d7e7..7d04c9d 100644 --- a/Source/Coinbase.Tests/Endpoints/ApiParameterTests.cs +++ b/Source/Coinbase.Tests/Endpoints/ApiParameterTests.cs @@ -1,5 +1,4 @@ using System; -using System.Net.Http; using System.Threading.Tasks; using Coinbase.Models; using FluentAssertions; @@ -13,8 +12,9 @@ public class ApiParameterTests : ServerTest private CoinbaseClient client; [SetUp] - public void BeforeEachTest() + public override void BeforeEachTest() { + base.BeforeEachTest(); client = new CoinbaseClient(new OAuthConfig {AccessToken = OAuthServerTest.OauthKey}); } @@ -26,8 +26,8 @@ public async Task withdraw Func>> a = async () => await client.Withdrawals.ListWithdrawalsAsync(accountId); Func>> b = async () => await client.Withdrawals.WithdrawalFundsAsync(accountId, null); - a.Should().Throw(); - b.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); } [Test] @@ -39,11 +39,10 @@ public async Task withdraw2 Func>> a = async () => await client.Withdrawals.GetWithdrawalAsync(accountId, withdrawlId); Func>> b = async () => await client.Withdrawals.CommitWithdrawalAsync(accountId, withdrawlId); - a.Should().Throw(); - b.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); } - - + [Test] public async Task transactions ( @@ -54,10 +53,10 @@ public async Task transactions Func>> c = async () => await client.Transactions.TransferMoneyAsync(accountId, null); Func>> d = async () => await client.Transactions.RequestMoneyAsync(accountId, null); - a.Should().Throw(); - b.Should().Throw(); - c.Should().Throw(); - d.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); + await c.Should().ThrowAsync(); + await d.Should().ThrowAsync(); } [Test] @@ -71,13 +70,12 @@ public async Task transactions2 Func> c = async () => await client.Transactions.ResendRequestMoneyAsync(accountId, txId); Func> d = async () => await client.Transactions.CancelRequestMoneyAsync(accountId, txId); - a.Should().Throw(); - b.Should().Throw(); - c.Should().Throw(); - d.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); + await c.Should().ThrowAsync(); + await d.Should().ThrowAsync(); } - [Test] public async Task notifications ( @@ -85,10 +83,9 @@ public async Task notifications { Func>> a = async () => await client.Notifications.GetNotificationAsync(notificationId); - a.Should().Throw(); + await a.Should().ThrowAsync(); } - [Test] public async Task deposits ( @@ -97,8 +94,8 @@ public async Task deposits Func>> a = async () => await client.Deposits.ListDepositsAsync(accountId); Func>> b = async () => await client.Deposits.DepositFundsAsync(accountId, null); - a.Should().Throw(); - b.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); } [Test] @@ -110,34 +107,8 @@ public async Task deposits2 Func>> a = async () => await client.Deposits.GetDepositAsync(accountId, depositId); Func>> b = async () => await client.Deposits.CommitDepositAsync(accountId, depositId); - a.Should().Throw(); - b.Should().Throw(); - } - - - [Test] - public async Task sells - ( - [Values(null, "", " ")]string accountId) - { - Func>> a = async () => await client.Sells.ListSellsAsync(accountId); - Func>> b = async () => await client.Sells.PlaceSellOrderAsync(accountId, null); - - a.Should().Throw(); - b.Should().Throw(); - } - - [Test] - public async Task sells2 - ( - [Values(null, "", " ", "fff")]string accountId, - [Values(null, "", " ")]string sellId) - { - Func>> a = async () => await client.Sells.GetSellAsync(accountId, sellId); - Func>> b = async () => await client.Sells.CommitSellAsync(accountId, sellId); - - a.Should().Throw(); - b.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); } [Test] @@ -147,17 +118,7 @@ public async Task paymentmethod { Func>> a = async () => await client.PaymentMethods.GetPaymentMethodAsync(paymentMethodId); - a.Should().Throw(); - } - - [Test] - public async Task user - ( - [Values(null, "", " ")]string userId) - { - Func>> a = async () => await client.Users.GetUserAsync(userId); - - a.Should().Throw(); + await a.Should().ThrowAsync(); } [Test] @@ -169,9 +130,9 @@ public async Task data Func>> b = async () => await client.Data.GetSellPriceAsync(currencyId); Func>> c = async () => await client.Data.GetSpotPriceAsync(currencyId); - a.Should().Throw(); - b.Should().Throw(); - c.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); + await c.Should().ThrowAsync(); } [Test] @@ -184,40 +145,10 @@ public async Task accounts Func>> c = async () => await client.Accounts.UpdateAccountAsync(accountId, null); Func> d = async () => await client.Accounts.DeleteAccountAsync(accountId); - a.Should().Throw(); - b.Should().Throw(); - c.Should().Throw(); - d.Should().Throw(); - } - - [Test] - public async Task buys - ( - [Values(null, "", " ")]string accountId) - { - var create = new PlaceBuy - { - Amount = 0.1m, - Currency = "BTC", - PaymentMethod = "B28EB04F-BD70-4308-90A1-96065283A001" - }; - - Func>> a = async () => await client.Buys.PlaceBuyOrderAsync(accountId, create); - - a.Should().Throw(); - } - - [Test] - public async Task buys2 - ( - [Values(null, "", " ", "fff")] string accountId, - [Values(null, "", " ")] string buyId) - { - Func>> a = async () => await client.Buys.CommitBuyAsync(accountId, buyId); - Func>> b = async () => await client.Buys.GetBuyAsync(accountId, buyId); - - a.Should().Throw(); - b.Should().Throw(); + await a.Should().ThrowAsync(); + await b.Should().ThrowAsync(); + await c.Should().ThrowAsync(); + await d.Should().ThrowAsync(); } } } diff --git a/Source/Coinbase.Tests/Endpoints/BuyTest.cs b/Source/Coinbase.Tests/Endpoints/BuyTest.cs deleted file mode 100644 index 7c9c18e..0000000 --- a/Source/Coinbase.Tests/Endpoints/BuyTest.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Coinbase.Models; -using FluentAssertions; -using NUnit.Framework; -using static Coinbase.Tests.Examples; - -namespace Coinbase.Tests.Endpoints -{ - public class BuyTests : OAuthServerTest - { - [Test] - public async Task can_list() - { - SetupServerPagedResponse(PaginationJson, $"{Buy1}"); - - var r = await client.Buys.ListBuysAsync("fff"); - - var truth = new PagedResponse - { - Pagination = PaginationModel, - Data = new[] - { - Buy1Model - } - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/buys") - .WithVerb(HttpMethod.Get); - } - - [Test] - public async Task can_get() - { - SetupServerSingleResponse(Buy1); - - var r = await client.Buys.GetBuyAsync("fff", "uuu"); - - var truth = new Response - { - Data = Buy1Model - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/buys/uuu") - .WithVerb(HttpMethod.Get); - } - - - - [Test] - public async Task can_place_buyorder() - { - SetupServerSingleResponse(Buy2); - - var create = new PlaceBuy - { - Amount = 0.1m, - Currency = "BTC", - PaymentMethod = "B28EB04F-BD70-4308-90A1-96065283A001" - }; - var r = await client.Buys.PlaceBuyOrderAsync("fff", create ); - - var truth = new Response - { - Data = Buy2Model - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveRequestBody( - @"{""amount"":0.1,""currency"":""BTC"",""payment_method"":""B28EB04F-BD70-4308-90A1-96065283A001"",""agree_btc_amount_varies"":false,""commit"":false,""quote"":false}"); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/buys") - .WithVerb(HttpMethod.Post); - } - - - [Test] - public async Task can_commit() - { - SetupServerSingleResponse(Buy2); - - var r = await client.Buys.CommitBuyAsync("fff", "uuu"); - - var truth = new Response - { - Data = Buy2Model - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/buys/uuu/commit") - .WithVerb(HttpMethod.Post); - } - } -} \ No newline at end of file diff --git a/Source/Coinbase.Tests/Endpoints/DepositTests.cs b/Source/Coinbase.Tests/Endpoints/DepositTests.cs index 89c020e..065dd38 100644 --- a/Source/Coinbase.Tests/Endpoints/DepositTests.cs +++ b/Source/Coinbase.Tests/Endpoints/DepositTests.cs @@ -1,101 +1,89 @@ -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; +using JsonSerializer = System.Text.Json.JsonSerializer; using Coinbase.Models; using FluentAssertions; using NUnit.Framework; +using System; +using System.Net.Http; +using System.Threading.Tasks; using static Coinbase.Tests.Examples; namespace Coinbase.Tests.Endpoints { + [TestFixture] public class DepositTests : OAuthServerTest { [Test] - public async Task can_list() + public async Task can_commit() { - SetupServerPagedResponse(PaginationJson, $"{Deposit1}"); + SetupServerSingleResponse(Deposit1); - var r = await client.Deposits.ListDepositsAsync("fff"); + var r = await client.Deposits.CommitDepositAsync("fff", "uuu"); + + var truth = new Response { Data = Deposit1Model }; - var truth = new PagedResponse - { - Pagination = PaginationModel, - Data = new[] - { - Deposit1Model - } - }; + truth.Should() + .BeEquivalentTo(r); - truth.Should().BeEquivalentTo(r); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/deposits/uuu/commit") + .WithVerb(HttpMethod.Post); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/deposits") - .WithVerb(HttpMethod.Get); + Console.WriteLine("*** UNIT TEST PASSED ***"); } [Test] - public async Task can_get() + public async Task can_depositfunds() { SetupServerSingleResponse(Deposit1); - var r = await client.Deposits.GetDepositAsync("fff", "uuu"); - - var truth = new Response - { - Data = Deposit1Model - }; + var create = new DepositFunds { Amount = 10.0m, Currency = "USD", PaymentMethod = "B28EB04F-BD70-4308-90A1-96065283A001" }; + var r = await client.Deposits.DepositFundsAsync("fff", create); - truth.Should().BeEquivalentTo(r); + var truth = new Response { Data = Deposit1Model }; - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/deposits/uuu") - .WithVerb(HttpMethod.Get); - } + truth.Should() + .BeEquivalentTo(r); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/deposits") + .WithRequestBody(JsonSerializer.Serialize(create)) + .WithVerb(HttpMethod.Post); + Console.WriteLine("*** UNIT TEST PASSED ***"); + } [Test] - public async Task can_depositfunds() + public async Task can_get() { SetupServerSingleResponse(Deposit1); - var create = new DepositFunds - { - Amount = 10.0m, - Currency = "USD", - PaymentMethod = "B28EB04F-BD70-4308-90A1-96065283A001" - }; - var r = await client.Deposits.DepositFundsAsync("fff", create ); + var r = await client.Deposits.GetDepositAsync("fff", "uuu"); - var truth = new Response - { - Data = Deposit1Model - }; + var truth = new Response { Data = Deposit1Model }; - truth.Should().BeEquivalentTo(r); + truth.Should() + .BeEquivalentTo(r); - server.ShouldHaveRequestBody( - @"{""amount"":10.0,""currency"":""USD"",""payment_method"":""B28EB04F-BD70-4308-90A1-96065283A001"",""commit"":false}"); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/deposits/uuu") + .WithVerb(HttpMethod.Get); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/deposits") - .WithVerb(HttpMethod.Post); + Console.WriteLine("*** UNIT TEST PASSED ***"); } - [Test] - public async Task can_commit() + public async Task can_list() { - SetupServerSingleResponse(Deposit1); + SetupServerPagedResponse(PaginationJson, $"{Deposit1}"); - var r = await client.Deposits.CommitDepositAsync("fff", "uuu"); + var r = await client.Deposits.ListDepositsAsync("fff"); + + var truth = new PagedResponse { Pagination = PaginationModel, Data = new[] { Deposit1Model } }; - var truth = new Response - { - Data = Deposit1Model - }; + truth.Should() + .BeEquivalentTo(r); - truth.Should().BeEquivalentTo(r); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/deposits") + .WithVerb(HttpMethod.Get); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/deposits/uuu/commit") - .WithVerb(HttpMethod.Post); + Console.WriteLine("*** UNIT TEST PASSED ***"); } } -} \ No newline at end of file +} diff --git a/Source/Coinbase.Tests/Endpoints/NotificationTests.cs b/Source/Coinbase.Tests/Endpoints/NotificationTests.cs index a15e19e..57941b1 100644 --- a/Source/Coinbase.Tests/Endpoints/NotificationTests.cs +++ b/Source/Coinbase.Tests/Endpoints/NotificationTests.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; using Coinbase.Models; using FluentAssertions; @@ -8,6 +7,7 @@ namespace Coinbase.Tests.Endpoints { + [TestFixture] public class NotificationTests : OAuthServerTest { [Test] @@ -28,7 +28,7 @@ public async Task can_list() truth.Should().BeEquivalentTo(r); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/notifications") + server.ShouldHaveCalled("https://api.coinbase.com/v2/notifications") .WithVerb(HttpMethod.Get); } @@ -46,8 +46,8 @@ public async Task can_get() truth.Should().BeEquivalentTo(r); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/notifications/fff") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/notifications/fff") .WithVerb(HttpMethod.Get); } } -} \ No newline at end of file +} diff --git a/Source/Coinbase.Tests/Endpoints/PaginationTests.cs b/Source/Coinbase.Tests/Endpoints/PaginationTests.cs index 831b4ec..82ed50e 100644 --- a/Source/Coinbase.Tests/Endpoints/PaginationTests.cs +++ b/Source/Coinbase.Tests/Endpoints/PaginationTests.cs @@ -1,7 +1,6 @@ -using System.Threading.Tasks; -using Coinbase.Models; +using Coinbase.Models; using NUnit.Framework; -using static Coinbase.Tests.Examples; +using System.Threading.Tasks; namespace Coinbase.Tests.Endpoints { @@ -12,7 +11,7 @@ public async Task page_accounts() { await client.Accounts.ListAccountsAsync(new PaginationOptions {Limit = 5, EndingBefore = "before", Order = "ooo", StartingAfter = "after"}); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts?limit=5&order=ooo&starting_after=after&ending_before=before"); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts?limit=5&order=ooo&starting_after=after&ending_before=before"); } [Test] @@ -20,7 +19,7 @@ public async Task page_addresses() { await client.Addresses.ListAddressesAsync("fff", new PaginationOptions { Limit = 5,Order = "ooo" }); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/addresses?limit=5&order=ooo"); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/addresses?limit=5&order=ooo"); } [Test] @@ -33,7 +32,7 @@ public async Task can_get_next_page() await client.GetNextPageAsync(p); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/next/thing?limit=5"); + server.ShouldHaveCalled("https://api.coinbase.com/v2/next/thing?limit=5"); } //[Test] @@ -46,7 +45,7 @@ public async Task can_get_next_page() // await client.PreviousPageAsync(p); - // server.ShouldHaveExactCall("https://api.coinbase.com/v2/prev/thing?limit=5"); + // server.ShouldHaveCalled("https://api.coinbase.com/v2/prev/thing?limit=5"); //} } } diff --git a/Source/Coinbase.Tests/Endpoints/PaymentMethodTest.cs b/Source/Coinbase.Tests/Endpoints/PaymentMethodTest.cs index f555b2c..fa47bd6 100644 --- a/Source/Coinbase.Tests/Endpoints/PaymentMethodTest.cs +++ b/Source/Coinbase.Tests/Endpoints/PaymentMethodTest.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; using Coinbase.Models; using FluentAssertions; @@ -29,7 +28,7 @@ public async Task can_list() truth.Should().BeEquivalentTo(r); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/payment-methods") + server.ShouldHaveCalled("https://api.coinbase.com/v2/payment-methods") .WithVerb(HttpMethod.Get); } @@ -47,8 +46,8 @@ public async Task can_get() truth.Should().BeEquivalentTo(r); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/payment-methods/fff") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/payment-methods/fff") .WithVerb(HttpMethod.Get); } } -} \ No newline at end of file +} diff --git a/Source/Coinbase.Tests/Endpoints/SellTest.cs b/Source/Coinbase.Tests/Endpoints/SellTest.cs deleted file mode 100644 index 6e61084..0000000 --- a/Source/Coinbase.Tests/Endpoints/SellTest.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Coinbase.Models; -using FluentAssertions; -using NUnit.Framework; -using static Coinbase.Tests.Examples; - -namespace Coinbase.Tests.Endpoints -{ - public class SellTests : OAuthServerTest - { - [Test] - public async Task can_list() - { - SetupServerPagedResponse(PaginationJson, $"{Sell1}"); - - var r = await client.Sells.ListSellsAsync("fff"); - - var truth = new PagedResponse - { - Pagination = PaginationModel, - Data = new[] - { - Sell1Model - } - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/sells") - .WithVerb(HttpMethod.Get); - } - - [Test] - public async Task can_get() - { - SetupServerSingleResponse(Sell1); - - var r = await client.Sells.GetSellAsync("fff", "uuu"); - - var truth = new Response - { - Data = Sell1Model - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/sells/uuu") - .WithVerb(HttpMethod.Get); - } - - - - [Test] - public async Task can_place_sellorder() - { - SetupServerSingleResponse(Sell2); - - var create = new PlaceSell - { - Amount = 10m, - Currency = "BTC", - PaymentMethod = "B28EB04F-BD70-4308-90A1-96065283A001" - }; - var r = await client.Sells.PlaceSellOrderAsync("fff", create ); - - var truth = new Response - { - Data = Sell2Model - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveRequestBody( - @"{""amount"":10.0,""currency"":""BTC"",""payment_method"":""B28EB04F-BD70-4308-90A1-96065283A001"",""agree_btc_amount_varies"":false,""commit"":false,""quote"":false}"); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/sells") - .WithVerb(HttpMethod.Post); - } - - - [Test] - public async Task can_commit() - { - SetupServerSingleResponse(Sell2); - - var r = await client.Sells.CommitSellAsync("fff", "uuu"); - - var truth = new Response - { - Data = Sell2Model - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/sells/uuu/commit") - .WithVerb(HttpMethod.Post); - } - } -} diff --git a/Source/Coinbase.Tests/Endpoints/TransactionTests.cs b/Source/Coinbase.Tests/Endpoints/TransactionTests.cs index e9467b9..febb2dd 100644 --- a/Source/Coinbase.Tests/Endpoints/TransactionTests.cs +++ b/Source/Coinbase.Tests/Endpoints/TransactionTests.cs @@ -1,9 +1,9 @@ -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; +using JsonSerializer = System.Text.Json.JsonSerializer; using Coinbase.Models; using FluentAssertions; using NUnit.Framework; +using System.Net.Http; +using System.Threading.Tasks; using static Coinbase.Tests.Examples; namespace Coinbase.Tests.Endpoints @@ -11,28 +11,21 @@ namespace Coinbase.Tests.Endpoints public class TransactionTests : OAuthServerTest { [Test] - public async Task can_list() + public async Task can_cancel() { - SetupServerPagedResponse(PaginationJson, $"{Transaction2},{Transaction3},{Transaction4},{Transaction5}"); + using var r = await client.Transactions.CancelRequestMoneyAsync("fff", "uuu"); - var r = await client.Transactions.ListTransactionsAsync("fff"); - - var truth = new PagedResponse - { - Pagination = PaginationModel, - Data = new[] - { - Transaction2Model, - Transaction3Model, - Transaction4Model, - Transaction5Model - } - }; + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions/uuu") + .WithVerb(HttpMethod.Delete); + } - truth.Should().BeEquivalentTo(r); + [Test] + public async Task can_complete() + { + using var r = await client.Transactions.CompleteRequestMoneyAsync("fff", "uuu"); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/transactions") - .WithVerb(HttpMethod.Get); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions/uuu/complete") + .WithVerb(HttpMethod.Post); } [Test] @@ -42,131 +35,103 @@ public async Task can_get() var r = await client.Transactions.GetTransactionAsync("fff", "uuu"); - var truth = new Response - { - Data = Transaction5Model - }; + var truth = new Response { Data = Transaction5Model }; - truth.Should().BeEquivalentTo(r); + truth.Should() + .BeEquivalentTo(r); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/transactions/uuu") - .WithVerb(HttpMethod.Get); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions/uuu") + .WithVerb(HttpMethod.Get); } - - [Test] - public async Task can_send() + public async Task can_list() { - SetupServerSingleResponse(Transaction6); - - var createTx = new CreateTransaction - { - Type = "send", - To = "1AUJ8z5RuHRTqD1eikyfUUetzGmdWLGkpT", - Amount = 0.1m, - Currency = "BTC", - Idem = "9316dd16-0c05" - }; - var r = await client.Transactions.SendMoneyAsync("fff", createTx ); + SetupServerPagedResponse(PaginationJson, $"{Transaction2},{Transaction3},{Transaction4},{Transaction5}"); - var truth = new Response - { - Data = Transaction6Model - }; + var r = await client.Transactions.ListTransactionsAsync("fff"); - truth.Should().BeEquivalentTo(r); + var truth = new PagedResponse + { + Pagination = PaginationModel, Data = new[] { Transaction2Model, Transaction3Model, Transaction4Model, Transaction5Model } + }; - server.ShouldHaveRequestBody( - "{\"type\":\"send\",\"to\":\"1AUJ8z5RuHRTqD1eikyfUUetzGmdWLGkpT\",\"amount\":0.1,\"currency\":\"BTC\",\"skip_notifications\":false,\"idem\":\"9316dd16-0c05\",\"to_financial_institution\":false}"); + truth.Should() + .BeEquivalentTo(r); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/transactions") - .WithVerb(HttpMethod.Post); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions") + .WithVerb(HttpMethod.Get); } [Test] - public async Task can_transfer() + public async Task can_request() { SetupServerSingleResponse(Transaction7); - var createTx = new CreateTransfer - { - Type = "send", - To = "1AUJ8z5RuHRTqD1eikyfUUetzGmdWLGkpT", - Amount = 0.1m, - Currency = "BTC" - }; - var r = await client.Transactions.TransferMoneyAsync("fff", createTx); + var create = new RequestMoney { Type = "request", To = "email@example.com", Amount = 0.1m, Currency = "BTC" }; + var r = await client.Transactions.RequestMoneyAsync("fff", create); - var truth = new Response - { - Data = Transaction7Model - }; + var truth = new Response { Data = Transaction7Model }; - truth.Should().BeEquivalentTo(r); + truth.Should() + .BeEquivalentTo(r); - server.ShouldHaveRequestBody( - @"{""type"":""send"",""to"":""1AUJ8z5RuHRTqD1eikyfUUetzGmdWLGkpT"",""amount"":0.1,""currency"":""BTC""}"); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions") + .WithVerb(HttpMethod.Post); + } + + [Test] + public async Task can_resend() + { + using var r = await client.Transactions.ResendRequestMoneyAsync("fff", "uuu"); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/transactions") - .WithVerb(HttpMethod.Post); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions/uuu/resend") + .WithVerb(HttpMethod.Post); } [Test] - public async Task can_request() + public async Task can_send() { - SetupServerSingleResponse(Transaction7); + SetupServerSingleResponse(Transaction6); - var create = new RequestMoney + var createTx = new CreateTransaction { - Type = "request", - To = "email@example.com", + Type = "send", + To = "1AUJ8z5RuHRTqD1eikyfUUetzGmdWLGkpT", Amount = 0.1m, - Currency = "BTC" - }; - var r = await client.Transactions.RequestMoneyAsync("fff", create); - - var truth = new Response - { - Data = Transaction7Model + Currency = "BTC", + Idem = "9316dd16-0c05" }; + var r = await client.Transactions.SendMoneyAsync("fff", createTx); + var truth = new Response { Data = Transaction6Model }; - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/transactions") - .WithVerb(HttpMethod.Post); - } - + truth.Should() + .BeEquivalentTo(r); - [Test] - public async Task can_compelte() - { - var r = await client.Transactions.CompleteRequestMoneyAsync("fff", "uuu"); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/transactions/uuu/complete") - .WithVerb(HttpMethod.Post); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions") + .WithRequestBody( + JsonSerializer.Serialize(createTx) + ) + .WithVerb(HttpMethod.Post); } - [Test] - public async Task can_resend() + public async Task can_transfer() { - var r = await client.Transactions.ResendRequestMoneyAsync("fff", "uuu"); + SetupServerSingleResponse(Transaction7); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/transactions/uuu/resend") - .WithVerb(HttpMethod.Post); - } + var createTx = new CreateTransfer { Type = "send", To = "1AUJ8z5RuHRTqD1eikyfUUetzGmdWLGkpT", Amount = 0.1m, Currency = "BTC" }; + var r = await client.Transactions.TransferMoneyAsync("fff", createTx); + var truth = new Response { Data = Transaction7Model }; - [Test] - public async Task can_cancel() - { - var r = await client.Transactions.CancelRequestMoneyAsync("fff", "uuu"); + truth.Should() + .BeEquivalentTo(r); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/transactions/uuu") - .WithVerb(HttpMethod.Delete); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/transactions") + .WithRequestBody(JsonSerializer.Serialize(createTx)) + .WithVerb(HttpMethod.Post); } - } -} \ No newline at end of file +} diff --git a/Source/Coinbase.Tests/Endpoints/UserTests.cs b/Source/Coinbase.Tests/Endpoints/UserTests.cs deleted file mode 100644 index b7dde0b..0000000 --- a/Source/Coinbase.Tests/Endpoints/UserTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Net.Http; -using System.Threading.Tasks; -using Coinbase.Models; -using FluentAssertions; -using NUnit.Framework; - -namespace Coinbase.Tests.Endpoints -{ - public class UserTests : OAuthServerTest - { - [Test] - public async Task can_get_user() - { - SetupServerSingleResponse(Examples.User); - - const string userId = "9da7a204-544e-5fd1-9a12-61176c5d4cd8"; - - var user = await client.Users.GetUserAsync(userId); - - var truth = new Response - { - Data = Examples.UserModel - }; - - user.Should().BeEquivalentTo(truth); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/users/{userId}") - .WithVerb(HttpMethod.Get); - } - - [Test] - public async Task can_get_current_user() - { - SetupServerSingleResponse(Examples.User); - - var user = await client.Users.GetCurrentUserAsync(); - - var truth = new Response - { - Data = Examples.UserModel - }; - - user.Should().BeEquivalentTo(truth); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/user") - .WithVerb(HttpMethod.Get); - } - - [Test] - public async Task can_get_auth_information() - { - SetupServerSingleResponse(Examples.Auth); - - var user = await client.Users.GetAuthInfoAsync(); - - var truth = new Response - { - Data = Examples.AuthModel - }; - - user.Should().BeEquivalentTo(truth); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/user/auth") - .WithVerb(HttpMethod.Get); - } - - [Test] - public async Task update_user() - { - SetupServerSingleResponse(Examples.UserWithNameChange("bbb ccc")); - - var user = await client.Users.UpdateUserAsync(new UserUpdate{ Name = "bbb ccc"}); - - var truth = new Response - { - Data = Examples.UserModel - }; - truth.Data.Name = "bbb ccc"; - - user.Should().BeEquivalentTo(truth); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/user") - .WithVerb(HttpMethod.Put); - } - - - } -} \ No newline at end of file diff --git a/Source/Coinbase.Tests/Endpoints/WithdrawlTests.cs b/Source/Coinbase.Tests/Endpoints/WithdrawalTests.cs similarity index 72% rename from Source/Coinbase.Tests/Endpoints/WithdrawlTests.cs rename to Source/Coinbase.Tests/Endpoints/WithdrawalTests.cs index 8dceb95..f1e058c 100644 --- a/Source/Coinbase.Tests/Endpoints/WithdrawlTests.cs +++ b/Source/Coinbase.Tests/Endpoints/WithdrawalTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using JsonSerializer = System.Text.Json.JsonSerializer; using System.Net.Http; using System.Threading.Tasks; using Coinbase.Models; @@ -8,28 +8,24 @@ namespace Coinbase.Tests.Endpoints { - public class WithdrawlTests : OAuthServerTest + public class WithdrawalTests : OAuthServerTest { [Test] - public async Task can_list() + public async Task can_commit() { - SetupServerPagedResponse(PaginationJson, $"{Withdrawal1}"); + SetupServerSingleResponse(Withdrawal1); - var r = await client.Withdrawals.ListWithdrawalsAsync("fff"); + var r = await client.Withdrawals.CommitWithdrawalAsync("fff", "uuu"); - var truth = new PagedResponse - { - Pagination = PaginationModel, - Data = new[] - { - Withdrawal1Model - } - }; + var truth = new Response + { + Data = Withdrawal1Model + }; truth.Should().BeEquivalentTo(r); - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/withdrawals") - .WithVerb(HttpMethod.Get); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/withdrawals/uuu/commit") + .WithVerb(HttpMethod.Post); } [Test] @@ -46,11 +42,31 @@ public async Task can_get() truth.Should().BeEquivalentTo(r); - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/withdrawals/uuu") + server.ShouldHaveCalled($"https://api.coinbase.com/v2/accounts/fff/withdrawals/uuu") .WithVerb(HttpMethod.Get); } + [Test] + public async Task can_list() + { + SetupServerPagedResponse(PaginationJson, $"{Withdrawal1}"); + + var r = await client.Withdrawals.ListWithdrawalsAsync("fff"); + + var truth = new PagedResponse + { + Pagination = PaginationModel, + Data = new[] + { + Withdrawal1Model + } + }; + + truth.Should().BeEquivalentTo(r); + server.ShouldHaveCalled("https://api.coinbase.com/v2/accounts/fff/withdrawals") + .WithVerb(HttpMethod.Get); + } [Test] public async Task can_withdrawal() @@ -72,30 +88,9 @@ public async Task can_withdrawal() truth.Should().BeEquivalentTo(r); - server.ShouldHaveRequestBody( - @"{""amount"":10.0,""currency"":""USD"",""payment_method"":""B28EB04F-BD70-4308-90A1-96065283A001"",""commit"":false}"); - - server.ShouldHaveExactCall($"https://api.coinbase.com/v2/accounts/fff/withdrawals") - .WithVerb(HttpMethod.Post); - } - - - [Test] - public async Task can_commit() - { - SetupServerSingleResponse(Withdrawal1); - - var r = await client.Withdrawals.CommitWithdrawalAsync("fff", "uuu"); - - var truth = new Response - { - Data = Withdrawal1Model - }; - - truth.Should().BeEquivalentTo(r); - - server.ShouldHaveExactCall("https://api.coinbase.com/v2/accounts/fff/withdrawals/uuu/commit") - .WithVerb(HttpMethod.Post); + server.ShouldHaveCalled($"https://api.coinbase.com/v2/accounts/fff/withdrawals") + .WithRequestBody(JsonSerializer.Serialize(create)) + .WithVerb(HttpMethod.Post); } } -} \ No newline at end of file +} diff --git a/Source/Coinbase.Tests/Examples.cs b/Source/Coinbase.Tests/Examples.cs index 60dbf25..1a6ed60 100644 --- a/Source/Coinbase.Tests/Examples.cs +++ b/Source/Coinbase.Tests/Examples.cs @@ -312,7 +312,7 @@ public static string Address1WithName(string name) Resource = "transaction", ResourcePath = "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/4117f7d6-5694-5b36-bc8f-847509850ea4", Network = null, - Buy = new Entity + Buy = new Buy { Id = "9e14d574-30fa-5d85-b02c-6be0d851d61d", Resource = "buy", diff --git a/Source/Coinbase.Tests/ExtensionsForTesting.cs b/Source/Coinbase.Tests/ExtensionsForTesting.cs index 76179a9..18a7502 100644 --- a/Source/Coinbase.Tests/ExtensionsForTesting.cs +++ b/Source/Coinbase.Tests/ExtensionsForTesting.cs @@ -19,18 +19,6 @@ public static string DumpString(this object obj) return JsonConvert.SerializeObject(obj, Formatting.Indented); } - // https://github.com/tmenier/Flurl/issues/323 - public static HttpCallAssertion ShouldHaveExactCall(this HttpTest test, string exactUrl) - { - test.CallLog.First().Request.Url.ToString().Should().Be(exactUrl); - return new HttpCallAssertion(test.CallLog); - } - public static HttpCallAssertion ShouldHaveRequestBody(this HttpTest test, string json) - { - test.CallLog.First().RequestBody.Should().Be(json); - return new HttpCallAssertion(test.CallLog); - } - public static bool IsAppVeyor(this OperatingSystem os) { return Environment.GetEnvironmentVariable("APPVEYOR").IsNotNullOrWhiteSpace(); diff --git a/Source/Coinbase.Tests/GitHubIssues/Issue51.cs b/Source/Coinbase.Tests/GitHubIssues/Issue51.cs index a6fe942..2a4c9c9 100644 --- a/Source/Coinbase.Tests/GitHubIssues/Issue51.cs +++ b/Source/Coinbase.Tests/GitHubIssues/Issue51.cs @@ -33,24 +33,6 @@ public class Issue51 : OAuthServerTest ""instant"": true }"; - [Test] - public async Task can_deser_sellorder() - { - SetupServerSingleResponse(SellOrder); - - var create = new PlaceSell - { - Amount = 10m, - Currency = "BTC", - PaymentMethod = "B28EB04F-BD70-4308-90A1-96065283A001" - }; - - Func>> action = async () => - await client.Sells.PlaceSellOrderAsync("fff", create); - - action.Should().NotThrow(); - } - private const string PaymentMethods = @"{ ""id"": ""ee12b3d9-7476-4f88-a7c4-b11ed8b8fa0a"", @@ -133,7 +115,7 @@ public async Task can_list_payment_methods() Func>> action = async () => await client.PaymentMethods.ListPaymentMethodsAsync(); - action.Should().NotThrow(); + await action.Should().NotThrowAsync(); } } diff --git a/Source/Coinbase.Tests/Integration/DataTests.cs b/Source/Coinbase.Tests/Integration/DataTests.cs index 05704ec..63b2f1f 100644 --- a/Source/Coinbase.Tests/Integration/DataTests.cs +++ b/Source/Coinbase.Tests/Integration/DataTests.cs @@ -21,17 +21,19 @@ public void BeforeAllTests() { if( !Environment.OSVersion.IsAppVeyor() && Process.GetProcessesByName("Fiddler").Any() ) { - var webProxy = new WebProxy("http://localhost.:8888", BypassOnLocal: false); - - FlurlHttp.Configure(settings => - { - settings.HttpClientFactory = new ProxyFactory(webProxy); - }); + FlurlHttp.Clients.WithDefaults(builder => builder.ConfigureInnerHandler( + hch => + { + hch.Proxy = new WebProxy("http://localhost.:8888", BypassOnLocal: false); + hch.UseProxy = true; + } + )); + } -#if NETFRAMEWORK + #if NETFRAMEWORK ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; -#endif + #endif } [SetUp] @@ -44,8 +46,8 @@ public void BeforeEachTest() public async Task can_get_currencies() { var r = await client.Data.GetCurrenciesAsync(); - var usd = r.Data.Where(c => c.Id == "USD").First(); - usd.Name.Should().StartWith("US Dollar"); + var usd = r.Data.First(c => "USD".Equals(c.Id)); + usd.Name.Should().StartWith("United States Dollar"); } [Test] @@ -65,6 +67,7 @@ public async Task can_get_buyprice() r.Data.Currency.Should().Be("USD"); r.Data.Base.Should().Be("ETH"); } + [Test] public async Task can_get_sellprice() { @@ -74,6 +77,7 @@ public async Task can_get_sellprice() r.Data.Currency.Should().Be("USD"); r.Data.Base.Should().Be("ETH"); } + [Test] public async Task can_get_spotprice() { @@ -92,23 +96,4 @@ public async Task can_get_time() r.Data.Iso.Should().BeCloseTo(DateTimeOffset.UtcNow, TimeSpan.FromHours(1)); } } - - public class ProxyFactory : DefaultHttpClientFactory - { - private readonly WebProxy proxy; - - public ProxyFactory(WebProxy proxy) - { - this.proxy = proxy; - } - - public override HttpMessageHandler CreateMessageHandler() - { - return new HttpClientHandler - { - Proxy = this.proxy, - UseProxy = true - }; - } - } } diff --git a/Source/Coinbase.Tests/Integration/IntegrationTests.cs b/Source/Coinbase.Tests/Integration/IntegrationTests.cs index 5e0aa22..e96f26f 100644 --- a/Source/Coinbase.Tests/Integration/IntegrationTests.cs +++ b/Source/Coinbase.Tests/Integration/IntegrationTests.cs @@ -37,13 +37,13 @@ public IntegrationTests() ReadSecrets(); - var webProxy = new WebProxy("http://localhost.:8888", BypassOnLocal: false); - - FlurlHttp.Configure(settings => - { - settings.HttpClientFactory = new ProxyFactory(webProxy); - }); - + FlurlHttp.Clients.WithDefaults(builder => builder.ConfigureInnerHandler( + hch => + { + hch.Proxy = new WebProxy("http://localhost.:8888", BypassOnLocal: false); + hch.UseProxy = true; + } + )); } protected void ReadSecrets() @@ -65,14 +65,6 @@ public OAuthTests() } - [Test] - public async Task can_get_auths() - { - client = new CoinbaseClient(new OAuthConfig { AccessToken = secrets.OAuthCode }); - var r = await client.Users.GetAuthInfoAsync(); - r.Dump(); - } - [Test] public async Task test_full_flow_and_expiration() { @@ -99,113 +91,5 @@ public async Task convert_code_to_token() var token = await OAuthHelper.GetAccessTokenAsync(secrets.OAuthCode, secrets.OAuthClientId, secrets.OAuthClientSecret, redirectUrl); token.Dump(); } - - [Test] - public async Task run_expired_token() - { - this.client = new CoinbaseClient(new OAuthConfig { AccessToken = secrets.OAuthAccessToken, RefreshToken = secrets.OAuthRefreshToken }) - .WithAutomaticOAuthTokenRefresh(secrets.OAuthClientId, secrets.OAuthClientSecret); - - var authInfo = await this.client.Users.GetAuthInfoAsync(); - authInfo.Dump(); - } - } - - [Explicit] - public class UserTests : IntegrationTests - { - protected CoinbaseClient client; - - public UserTests() - { - client = new CoinbaseClient(new ApiKeyConfig { ApiKey = secrets.ApiKey, ApiSecret = secrets.ApiSecret}); - } - - [Test] - public async Task can_get_auths() - { - var r = await client.Users.GetAuthInfoAsync(); - r.Dump(); - } - - [Test] - public async Task check_account_list() - { - var r = await client.Accounts.ListAccountsAsync(); - r.Dump(); - } - - [Test] - public async Task check_account_transactions() - { - var r = await client.Transactions.ListTransactionsAsync("fff"); - - r.Dump(); - } - - [Test] - public async Task check_invalid_account() - { - var r = await client.Accounts.GetAccountAsync("fff"); - r.Dump(); - } - - [Test] - public async Task test_state() - { - var accounts = await client.Accounts.ListAccountsAsync(); - var ethAccount = accounts.Data.FirstOrDefault(x => x.Name == "ETH Wallet"); - var ethAddresses = await client.Addresses.ListAddressesAsync(ethAccount.Id); - var ethAddress = ethAddresses.Data.FirstOrDefault(); - var ethTransactions = await client.Transactions.ListTransactionsAsync(ethAccount.Id); - } - - - [Test] - public async Task test_paged_response() - { - var accounts = await client.Accounts.ListAccountsAsync(); - var btcWallet = accounts.Data.First(a => a.Name.StartsWith("BTC Wallet")); - - var page1 = await client.Addresses.ListAddressesAsync(btcWallet.Id, new PaginationOptions{Limit = 1}); - page1.Dump(); - - var page2 = await client.GetNextPageAsync(page1); - page2.Dump(); - - var page3 = await client.GetNextPageAsync(page2); - page3.Dump(); - //var prevPage = await client.PreviousPageAsync(page3); - - //prevPage.Dump(); - - //prevPage.Should().BeEquivalentTo(page1); - } - - [Test] - public async Task can_hoist_response() - { - bool myCustomActionWasCalled = false; - client.Configure(cf => - { - cf.AfterCall = http => - { - myCustomActionWasCalled = true; - "AfterCall action set by user.".Dump(); - }; - }); - - var list = await client - .AllowAnyHttpStatus() - .HoistResponse(out var responseGetter) - .Accounts - .ListAccountsAsync(); - - var response = responseGetter(); - - response.Should().NotBeNull(); - response.StatusCode.Should().NotBe(0); - myCustomActionWasCalled.Should().BeTrue(); - } } } diff --git a/Source/Coinbase.Tests/OAuthHelperTests.cs b/Source/Coinbase.Tests/OAuthHelperTests.cs index ddca6ac..e869d4f 100644 --- a/Source/Coinbase.Tests/OAuthHelperTests.cs +++ b/Source/Coinbase.Tests/OAuthHelperTests.cs @@ -45,7 +45,7 @@ public async Task can_create_authorization_url() var response = await authUrl.GetAsync(); - server.ShouldHaveExactCall(url); + server.ShouldHaveCalled(url); } @@ -56,7 +56,7 @@ public async Task can_revoke_token() var x = await OAuthHelper.RevokeTokenAsync("fff", "vvv"); - server.ShouldHaveExactCall("https://api.coinbase.com/oauth/revoke") + server.ShouldHaveCalled("https://api.coinbase.com/oauth/revoke") .WithVerb(HttpMethod.Post) .WithRequestBody("token=fff&access_token=vvv"); } @@ -81,7 +81,7 @@ public async Task can_get_access_token() clientSecret:"3a21f08c585df35c14c0c43b832640b29a3a3a18e5c54d5401f08c87c8be0b20", redirectUri: "http://localhost:8080/callback"); - server.ShouldHaveExactCall("https://api.coinbase.com/oauth/token") + server.ShouldHaveCalled("https://api.coinbase.com/oauth/token") .WithVerb(HttpMethod.Post) .WithRequestBody("grant_type=authorization_code" + "&code=4c666b5c0c0d9d3140f2e0776cbe245f3143011d82b7a2c2a590cc7e20b79ae8" + @@ -115,7 +115,7 @@ public async Task can_refresh_token() var token = await OAuthHelper.RenewAccessAsync("refresh", "clientid", "clientsecret"); - server.ShouldHaveExactCall("https://api.coinbase.com/oauth/token") + server.ShouldHaveCalled("https://api.coinbase.com/oauth/token") .WithVerb(HttpMethod.Post) .WithRequestBody("grant_type=refresh_token" + "&refresh_token=refresh" + diff --git a/Source/Coinbase.Tests/OAuthTests/OAuthHelperTests.cs b/Source/Coinbase.Tests/OAuthTests/OAuthHelperTests.cs index b73f8d4..51a2f5c 100644 --- a/Source/Coinbase.Tests/OAuthTests/OAuthHelperTests.cs +++ b/Source/Coinbase.Tests/OAuthTests/OAuthHelperTests.cs @@ -45,7 +45,7 @@ public async Task can_create_authorization_url() var response = await authUrl.GetAsync(); - server.ShouldHaveExactCall(url); + server.ShouldHaveCalled(url); } @@ -56,7 +56,7 @@ public async Task can_revoke_token() var x = await OAuthHelper.RevokeTokenAsync("fff", "vvv"); - server.ShouldHaveExactCall("https://api.coinbase.com/oauth/revoke") + server.ShouldHaveCalled("https://api.coinbase.com/oauth/revoke") .WithVerb(HttpMethod.Post) .WithRequestBody("token=fff&access_token=vvv"); } @@ -81,7 +81,7 @@ public async Task can_get_access_token() clientSecret:"3a21f08c585df35c14c0c43b832640b29a3a3a18e5c54d5401f08c87c8be0b20", redirectUri: "http://localhost:8080/callback"); - server.ShouldHaveExactCall("https://api.coinbase.com/oauth/token") + server.ShouldHaveCalled("https://api.coinbase.com/oauth/token") .WithVerb(HttpMethod.Post) .WithRequestBody("grant_type=authorization_code" + "&code=4c666b5c0c0d9d3140f2e0776cbe245f3143011d82b7a2c2a590cc7e20b79ae8" + @@ -115,7 +115,7 @@ public async Task can_refresh_token() var token = await OAuthHelper.RenewAccessAsync("refresh", "clientid", "clientsecret"); - server.ShouldHaveExactCall("https://api.coinbase.com/oauth/token") + server.ShouldHaveCalled("https://api.coinbase.com/oauth/token") .WithVerb(HttpMethod.Post) .WithRequestBody("grant_type=refresh_token" + "&refresh_token=refresh" + diff --git a/Source/Coinbase.Tests/OAuthTests/TokenTests.cs b/Source/Coinbase.Tests/OAuthTests/TokenTests.cs index bbe9824..ffb6a1b 100644 --- a/Source/Coinbase.Tests/OAuthTests/TokenTests.cs +++ b/Source/Coinbase.Tests/OAuthTests/TokenTests.cs @@ -16,91 +16,6 @@ public void BeforeEachTest() { client = new CoinbaseClient(new OAuthConfig(){ AccessToken = "zzz"}); } - [Test] - public async Task auto_refresh_token() - { - //simulate the expired response. - var expiredResponse = @"{""errors"":[{""id"":""expired_token"",""message"":""The access token is expired""}]}"; - server.RespondWith(expiredResponse, status:401); - - - //simulate the refresh response. - var refreshResponse = @"{ -""access_token"":""aaa"", -""token_type"":""bearer"", -""expires_in"":7200, -""refresh_token"":""bbb"", -""scope"":""all"", -""created_at"":1542649114 -}"; - server.RespondWith(refreshResponse, status: 200); - - //simulate the actual successful response after token refresh. - SetupServerSingleResponse(Examples.User); - - //enable automatic refresh - client.WithAutomaticOAuthTokenRefresh("clientId", "clientSecret"); - - var response = await client.Users.GetCurrentUserAsync(); - - response.Dump(); - - var config = client.Config as OAuthConfig; - config.AccessToken.Should().Be("aaa"); - config.RefreshToken.Should().Be("bbb"); - - Examples.UserModel.Should().BeEquivalentTo(response.Data); - - server.ShouldHaveMadeACall() - .WithHeader(HeaderNames.Version, CoinbaseClient.ApiVersionDate) - .WithHeader("User-Agent", CoinbaseClient.UserAgent) - .WithHeader("Authorization", $"Bearer aaa"); - } - - [Test] - public async Task auto_refresh_token_with_callback() - { - //simulate the expired response. - var expiredResponse = @"{""errors"":[{""id"":""expired_token"",""message"":""The access token is expired""}]}"; - server.RespondWith(expiredResponse, status: 401); - - //simulate the refresh response. - var refreshResponse = @"{ -""access_token"":""aaa"", -""token_type"":""bearer"", -""expires_in"":7200, -""refresh_token"":""bbb"", -""scope"":""all"", -""created_at"":1542649114 -}"; - server.RespondWith(refreshResponse, status: 200); - - //simulate the actual successful response after token refresh. - SetupServerSingleResponse(Examples.User); - - //enable automatic refresh - client.WithAutomaticOAuthTokenRefresh("clientId", "clientSecret", o => - { - o.AccessToken.Should().Be("aaa"); - o.RefreshToken.Should().Be("bbb"); - return Task.FromResult(0); - }); - - var response = await client.Users.GetCurrentUserAsync(); - - response.Dump(); - - var config = client.Config as OAuthConfig; - config.AccessToken.Should().Be("aaa"); - config.RefreshToken.Should().Be("bbb"); - - Examples.UserModel.Should().BeEquivalentTo(response.Data); - - server.ShouldHaveMadeACall() - .WithHeader(HeaderNames.Version, CoinbaseClient.ApiVersionDate) - .WithHeader("User-Agent", CoinbaseClient.UserAgent) - .WithHeader("Authorization", $"Bearer aaa"); - } } } diff --git a/Source/Coinbase.Tests/ServerTest.cs b/Source/Coinbase.Tests/ServerTest.cs index b82e961..9d8b5df 100644 --- a/Source/Coinbase.Tests/ServerTest.cs +++ b/Source/Coinbase.Tests/ServerTest.cs @@ -1,5 +1,6 @@ using Flurl.Http.Testing; using NUnit.Framework; +using System; namespace Coinbase.Tests { @@ -8,13 +9,13 @@ public class ServerTest protected HttpTest server; [SetUp] - public void BeforeEachTest() + public virtual void BeforeEachTest() { server = new HttpTest(); } [TearDown] - public void AfterEachTest() + public virtual void AfterEachTest() { this.server.Dispose(); } @@ -29,6 +30,13 @@ protected void SetupServerPagedResponse(string pageJson, string dataJson) .Replace("{pageJson}", pageJson); server.RespondWith(json); + + Console.WriteLine("Anticipated server response:"); + Console.WriteLine("---"); + Console.WriteLine(); + Console.WriteLine(json); + Console.WriteLine(); + Console.WriteLine("---"); } protected void SetupServerSingleResponse(string dataJson) @@ -39,6 +47,13 @@ protected void SetupServerSingleResponse(string dataJson) ".Replace("{dataJson}", dataJson); server.RespondWith(json); + + Console.WriteLine("Anticipated server response:"); + Console.WriteLine("---"); + Console.WriteLine(); + Console.WriteLine(json); + Console.WriteLine(); + Console.WriteLine("---"); } } @@ -49,15 +64,17 @@ public class OAuthServerTest : ServerTest public const string OauthKey = "369ECD3F-2D00-4D7A-ACDB-92C2DC35A878"; [SetUp] - public void BeforeEachTest() + public override void BeforeEachTest() { + base.BeforeEachTest(); client = new CoinbaseClient(new OAuthConfig{AccessToken = OauthKey}); } [TearDown] - public void AfterEachTest() + public override void AfterEachTest() { EnsureEveryRequestHasCorrectHeaders(); + base.AfterEachTest(); } private void EnsureEveryRequestHasCorrectHeaders() diff --git a/Source/Coinbase/Coinbase.csproj b/Source/Coinbase/Coinbase.csproj index e51c785..599dc57 100644 --- a/Source/Coinbase/Coinbase.csproj +++ b/Source/Coinbase/Coinbase.csproj @@ -5,7 +5,7 @@ 0.0.0-localbuild Brian Chavez - net461;netstandard2.0 + net462;net6.0 true @@ -29,9 +29,9 @@ $(DefineConstants);STANDARD - - - - + + + + \ No newline at end of file diff --git a/Source/Coinbase/CoinbaseClient.Accounts.cs b/Source/Coinbase/CoinbaseClient.Accounts.cs index 6999bae..ebd1c8b 100644 --- a/Source/Coinbase/CoinbaseClient.Accounts.cs +++ b/Source/Coinbase/CoinbaseClient.Accounts.cs @@ -4,39 +4,47 @@ using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { public interface IAccountsEndpoint { /// - /// Lists current user’s accounts to which the authentication method has access to. + /// Removes user’s account. In order to remove an account it can’t be: + /// * Primary account + /// * Account with non-zero balance + /// * Fiat account + /// * Vault with a pending withdrawal /// - Task> ListAccountsAsync(PaginationOptions pagination = null, CancellationToken cancellationToken = default); + Task DeleteAccountAsync(string accountId, CancellationToken cancellationToken = default); /// /// Show current user’s account. To access the primary account for a given currency, a currency string (BTC or ETH) can be used instead of the account id in the URL. /// Task> GetAccountAsync(string accountId, CancellationToken cancellationToken = default); + /// + /// Lists current user’s accounts to which the authentication method has access to. + /// + Task> ListAccountsAsync(PaginationOptions pagination = null, CancellationToken cancellationToken = default); /// /// Promote an account as primary account. /// + /// If the operation does not work, a Response<Account> + /// reference is returned having the account data, but it is not set to + /// primary. Task> SetAccountAsPrimaryAsync(string accountId, CancellationToken cancellationToken = default); /// /// Modifies user’s account. /// + /// Callers must check the result of this method to see + /// whether the update actually occurred, as this method returns + /// an instance of the Account model corresponding to the + /// specified regardless of whether + /// the update succeeded. Task> UpdateAccountAsync(string accountId, UpdateAccount updateAccount, CancellationToken cancellationToken = default); - - /// - /// Removes user’s account. In order to remove an account it can’t be: - /// * Primary account - /// * Account with non-zero balance - /// * Fiat account - /// * Vault with a pending withdrawal - /// - Task DeleteAccountAsync(string accountId, CancellationToken cancellationToken = default); } @@ -45,63 +53,74 @@ public partial class CoinbaseClient : IAccountsEndpoint public IAccountsEndpoint Accounts => this; /// - /// Lists current user’s accounts to which the authentication method has access to. + /// Removes user’s account. In order to remove an account it can’t be: + /// * Primary account + /// * Account with non-zero balance + /// * Fiat account + /// * Vault with a pending withdrawal /// - Task> IAccountsEndpoint.ListAccountsAsync(PaginationOptions pagination, CancellationToken cancellationToken) + async Task IAccountsEndpoint.DeleteAccountAsync(string accountId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + return await Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId)) + .DeleteAsync(cancellationToken: cancellationToken); } /// /// Show current user’s account. To access the primary account for a given currency, a currency string (BTC or ETH) can be used instead of the account id in the URL. /// - Task> IAccountsEndpoint.GetAccountAsync(string accountId, CancellationToken cancellationToken) + public async Task> GetAccountAsync(string accountId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId)).GetStringAsync(cancellationToken: cancellationToken); + if (string.IsNullOrWhiteSpace(responseBody)) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - /// Promote an account as primary account. + /// Lists current user’s accounts to which the authentication method has access to. /// - Task> IAccountsEndpoint.SetAccountAsPrimaryAsync(string accountId, CancellationToken cancellationToken) + async Task> IAccountsEndpoint.ListAccountsAsync(PaginationOptions pagination, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "primary") - .WithClient(this) - .PostJsonAsync(null, cancellationToken) - .ReceiveJson>(); + var responseBody = await Request(AccountsEndpoint.WithPagination(pagination)) + .GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) return default; + + return JsonConvert.DeserializeObject>(responseBody); } /// - /// Modifies user’s account. + /// Promote an account as primary account. /// - Task> IAccountsEndpoint.UpdateAccountAsync(string accountId, UpdateAccount updateAccount, CancellationToken cancellationToken) + /// If the operation does not work, a Response<Account> + /// reference is returned having the account data, but it is not set to + /// primary. + async Task> IAccountsEndpoint.SetAccountAsPrimaryAsync(string accountId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId) - .WithClient(this) - .PutJsonAsync(updateAccount, cancellationToken) - .ReceiveJson>(); - } + using var response = Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, "primary")) + .PostJsonAsync(null, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if( string.IsNullOrWhiteSpace(responseBody) ) + return await GetAccountAsync(accountId, cancellationToken); + return JsonConvert.DeserializeObject>(responseBody); + } /// - /// Removes user’s account. In order to remove an account it can’t be: - /// * Primary account - /// * Account with non-zero balance - /// * Fiat account - /// * Vault with a pending withdrawal + /// Modifies user’s account. /// - Task IAccountsEndpoint.DeleteAccountAsync(string accountId, CancellationToken cancellationToken) + /// Callers must check the result of this method to see + /// whether the update actually occurred, as this method returns + /// an instance of the Account model corresponding to the + /// specified regardless of whether + /// the update succeeded. + async Task> IAccountsEndpoint.UpdateAccountAsync(string accountId, UpdateAccount updateAccount, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId) - .WithClient(this) - .DeleteAsync(cancellationToken); + using var response = Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId)) + .PutJsonAsync(updateAccount, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if( string.IsNullOrWhiteSpace(responseBody) ) + return await GetAccountAsync(accountId, cancellationToken); + + return JsonConvert.DeserializeObject>(responseBody); } } } diff --git a/Source/Coinbase/CoinbaseClient.Addresses.cs b/Source/Coinbase/CoinbaseClient.Addresses.cs index a2e7cc9..7271131 100644 --- a/Source/Coinbase/CoinbaseClient.Addresses.cs +++ b/Source/Coinbase/CoinbaseClient.Addresses.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { @@ -29,52 +30,57 @@ public interface IAddressesEndpoint /// Task> CreateAddressAsync(string accountId, CreateAddress createAddress, CancellationToken cancellationToken = default); } - - + public partial class CoinbaseClient : IAddressesEndpoint { public IAddressesEndpoint Addresses => this; - /// - Task> IAddressesEndpoint.ListAddressesAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) + /// + async Task> IAddressesEndpoint.ListAddressesAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "addresses") - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request( + AccountsEndpoint.AppendPathSegmentsRequire(accountId, "addresses") + .WithPagination(pagination) + ).GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) return new PagedResponse(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - Task> IAddressesEndpoint.GetAddressAsync(string accountId, string addressId, CancellationToken cancellationToken) + async Task> IAddressesEndpoint.GetAddressAsync(string accountId, string addressId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "addresses", addressId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request( + AccountsEndpoint.AppendPathSegmentsRequire(accountId, "addresses", addressId) + ).GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - Task> IAddressesEndpoint.ListAddressTransactionsAsync(string accountId, string addressId, PaginationOptions pagination, CancellationToken cancellationToken) + async Task> IAddressesEndpoint.ListAddressTransactionsAsync(string accountId, string addressId, PaginationOptions pagination, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "addresses", addressId, "transactions") - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "addresses", addressId, "transactions") + .WithPagination(pagination) + ).GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) return new PagedResponse(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - Task> IAddressesEndpoint.CreateAddressAsync(string accountId, CreateAddress createAddress, CancellationToken cancellationToken) + async Task> IAddressesEndpoint.CreateAddressAsync(string accountId, CreateAddress createAddress, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "addresses") - .WithClient(this) - .PostJsonAsync(createAddress, cancellationToken) - .ReceiveJson>(); - } - - + using var response = Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, "addresses")) + .PostJsonAsync(createAddress, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + return JsonConvert.DeserializeObject>(responseBody); + } } } diff --git a/Source/Coinbase/CoinbaseClient.Buys.cs b/Source/Coinbase/CoinbaseClient.Buys.cs deleted file mode 100644 index b465b04..0000000 --- a/Source/Coinbase/CoinbaseClient.Buys.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Coinbase.Models; -using Flurl.Http; - -namespace Coinbase -{ - public interface IBuysEndpoint - { - /// - /// Lists buys for an account. - /// - Task> ListBuysAsync(string accountId, PaginationOptions pagination = null, CancellationToken cancellationToken = default); - - /// - /// Get an individual buy. - /// - Task> GetBuyAsync(string accountId, string buyId, CancellationToken cancellationToken = default); - - /// - /// Buys a user-defined amount of bitcoin, bitcoin cash, litecoin or ethereum. - /// There are two ways to define buy amounts–you can use either the amount or the total parameter: - /// 1. When supplying amount, you’ll get the amount of bitcoin, bitcoin cash, litecoin or ethereum defined.With amount it’s recommended to use BTC or ETH as the currency value, but you can always specify a fiat currency and and the amount will be converted to BTC or ETH respectively. - /// 2. When supplying total, your payment method will be debited the total amount and you’ll get the amount in BTC or ETH after fees have been reduced from the total.With total it’s recommended to use the currency of the payment method as the currency parameter, but you can always specify a different currency and it will be converted. - /// Given the price of digital currency depends on the time of the call and on the amount of purchase, it’s recommended to use the commit: false parameter to create an uncommitted buy to show the confirmation for the user or get the final quote, and commit that with a separate request. - /// If you need to query the buy price without locking in the buy, you can use quote: true option.This returns an unsaved buy and unlike commit: false, this buy can’t be completed.This option is useful when you need to show the detailed buy price quote for the user when they are filling a form or similar situation. - /// - Task> PlaceBuyOrderAsync(string accountId, PlaceBuy placeBuy, CancellationToken cancellationToken = default); - - /// - /// Completes a buy that is created in commit: false state. - /// If the exchange rate has changed since the buy was created, this call will fail with the error “The exchange rate updated while you were waiting.The new total is shown below”. - /// The buy’s total will also be updated.You can repeat the /commit call to accept the new values and start the buy at the new rates. - /// - Task> CommitBuyAsync(string accountId, string buyId, CancellationToken cancellationToken = default); - } - - public partial class CoinbaseClient : IBuysEndpoint - { - public IBuysEndpoint Buys => this; - - /// - /// Lists buys for an account. - /// - Task> IBuysEndpoint.ListBuysAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "buys") - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } - - /// - /// Get an individual buy. - /// - Task> IBuysEndpoint.GetBuyAsync(string accountId, string buyId, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "buys", buyId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } - - /// - /// Buys a user-defined amount of bitcoin, bitcoin cash, litecoin or ethereum. - /// There are two ways to define buy amounts–you can use either the amount or the total parameter: - /// 1. When supplying amount, you’ll get the amount of bitcoin, bitcoin cash, litecoin or ethereum defined.With amount it’s recommended to use BTC or ETH as the currency value, but you can always specify a fiat currency and and the amount will be converted to BTC or ETH respectively. - /// 2. When supplying total, your payment method will be debited the total amount and you’ll get the amount in BTC or ETH after fees have been reduced from the total.With total it’s recommended to use the currency of the payment method as the currency parameter, but you can always specify a different currency and it will be converted. - /// Given the price of digital currency depends on the time of the call and on the amount of purchase, it’s recommended to use the commit: false parameter to create an uncommitted buy to show the confirmation for the user or get the final quote, and commit that with a separate request. - /// If you need to query the buy price without locking in the buy, you can use quote: true option.This returns an unsaved buy and unlike commit: false, this buy can’t be completed.This option is useful when you need to show the detailed buy price quote for the user when they are filling a form or similar situation. - /// - Task> IBuysEndpoint.PlaceBuyOrderAsync(string accountId, PlaceBuy placeBuy, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "buys") - .WithClient(this) - .PostJsonAsync(placeBuy, cancellationToken) - .ReceiveJson>(); - } - - - /// - /// Completes a buy that is created in commit: false state. - /// If the exchange rate has changed since the buy was created, this call will fail with the error “The exchange rate updated while you were waiting.The new total is shown below”. - /// The buy’s total will also be updated.You can repeat the /commit call to accept the new values and start the buy at the new rates. - /// - Task> IBuysEndpoint.CommitBuyAsync(string accountId, string buyId, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "buys", buyId, "commit") - .WithClient(this) - .PostJsonAsync(null, cancellationToken) - .ReceiveJson>(); - } - - - } -} diff --git a/Source/Coinbase/CoinbaseClient.Data.cs b/Source/Coinbase/CoinbaseClient.Data.cs index 3ff9202..af5dd3f 100644 --- a/Source/Coinbase/CoinbaseClient.Data.cs +++ b/Source/Coinbase/CoinbaseClient.Data.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { @@ -57,12 +58,18 @@ public partial class CoinbaseClient : IDataEndpoint /// Note that exchange rates fluctuates so the price is only correct for seconds at the time.This buy price includes standard Coinbase fee (1%) but excludes any other fees including bank fees. /// /// Currency pair such as BTC-USD, ETH-USD, etc. - Task> IDataEndpoint.GetBuyPriceAsync(string currencyPair, CancellationToken cancellationToken) + async Task> IDataEndpoint.GetBuyPriceAsync(string currencyPair, CancellationToken cancellationToken) { - return this.PricesEndpoint - .WithClient(this) - .AppendPathSegmentsRequire(currencyPair, "buy") - .GetJsonAsync>(cancellationToken); + var responseBody = await Request( + PricesEndpoint + .AppendPathSegmentsRequire(currencyPair, "buy") + ).GetStringAsync( + cancellationToken: cancellationToken + ); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// @@ -70,12 +77,18 @@ Task> IDataEndpoint.GetBuyPriceAsync(string currencyPair, Cancel /// Note that exchange rates fluctuates so the price is only correct for seconds at the time.This sell price includes standard Coinbase fee (1%) but excludes any other fees including bank fees. /// /// Currency pair such as BTC-USD, ETH-USD, etc. - Task> IDataEndpoint.GetSellPriceAsync(string currencyPair, CancellationToken cancellationToken) + async Task> IDataEndpoint.GetSellPriceAsync(string currencyPair, CancellationToken cancellationToken) { - return this.PricesEndpoint - .WithClient(this) - .AppendPathSegmentsRequire(currencyPair, "sell") - .GetJsonAsync>(cancellationToken); + var responseBody = await Request( + PricesEndpoint + .AppendPathSegmentsRequire(currencyPair, "sell") + ).GetStringAsync( + cancellationToken: cancellationToken + ); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// @@ -84,48 +97,55 @@ Task> IDataEndpoint.GetSellPriceAsync(string currencyPair, Cance /// /// /// - Task> IDataEndpoint.GetSpotPriceAsync(string currencyPair, DateTime? date, CancellationToken cancellationToken) + async Task> IDataEndpoint.GetSpotPriceAsync(string currencyPair, DateTime? date, CancellationToken cancellationToken) { - var req = this.PricesEndpoint - .WithClient(this) - .AppendPathSegmentsRequire(currencyPair, "spot"); - - if (!(date is null)) - { - req = req.SetQueryParam("date", date.Value.ToString("yyyy-MM-dd")); - } - - return req.GetJsonAsync>(cancellationToken); + /* added range checking to the date, to make sure it is between MinValue and MaxValue (exclusive) */ + var req = date is null || DateTime.MinValue.Equals(date) || DateTime.MaxValue.Equals(date) + ? Request(PricesEndpoint.AppendPathSegmentsRequire(currencyPair, "spot")) + : Request( + PricesEndpoint.AppendPathSegmentsRequire(currencyPair, "spot") + .SetQueryParam("date", date.Value.ToString("yyyy-MM-dd")) + ); + + var responseBody = await req.GetStringAsync(cancellationToken: cancellationToken); + if (string.IsNullOrWhiteSpace(responseBody)) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - /// Get current exchange rates. Default base currency is USD but it can be defined as any supported currency. Returned rates will define the exchange rate for one unit of the base currency. + /// Get current exchange rates. Default base currency is USD, but it can be defined as any supported currency. Returned rates will define the exchange rate for one unit of the base currency. /// /// Base currency (default: USD) - Task> IDataEndpoint.GetExchangeRatesAsync(string currency, CancellationToken cancellationToken) + async Task> IDataEndpoint.GetExchangeRatesAsync(string currency, CancellationToken cancellationToken) { - var req = this.ExchangeRatesEndpoint - .WithClient(this); - - if (!(currency is null)) - { - req.SetQueryParam("currency", currency); - } - - return req.GetJsonAsync>(cancellationToken); + var req = string.IsNullOrWhiteSpace(currency) ? + Request(ExchangeRatesEndpoint) + : Request( + ExchangeRatesEndpoint + .SetQueryParam("currency", currency) + ); + + var responseBody = await req.GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// /// List known currencies. Currency codes will conform to the ISO 4217 standard where possible. Currencies which have or had no representation in ISO 4217 may use a custom code (e.g. BTC). /// - Task> IDataEndpoint.GetCurrenciesAsync(PaginationOptions pagination, CancellationToken cancellationToken) + async Task> IDataEndpoint.GetCurrenciesAsync(PaginationOptions pagination, CancellationToken cancellationToken) { - return this.CurrenciesEndpoint - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } + var responseBody = await Request(CurrenciesEndpoint.WithPagination(pagination)) + .GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new PagedResponse(); + return JsonConvert.DeserializeObject>(responseBody); + } /// /// Get the API server time. @@ -141,8 +161,7 @@ Task> IDataEndpoint.GetCurrentTimeAsync(CancellationToken cancell return this.TimeEndpoint .WithHeader(HeaderNames.Version, ApiVersionDate) .WithHeader("User-Agent", UserAgent) - .GetJsonAsync>(cancellationToken); + .GetJsonAsync>(cancellationToken: cancellationToken); } - } } diff --git a/Source/Coinbase/CoinbaseClient.Deposits.cs b/Source/Coinbase/CoinbaseClient.Deposits.cs index c788b9c..e6b3d72 100644 --- a/Source/Coinbase/CoinbaseClient.Deposits.cs +++ b/Source/Coinbase/CoinbaseClient.Deposits.cs @@ -1,26 +1,28 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { - public interface IDepositsEndpoint { /// /// Lists deposits for an account. /// Task> ListDepositsAsync(string accountId, PaginationOptions pagination = null, CancellationToken cancellationToken = default); + /// /// Show an individual deposit. /// Task> GetDepositAsync(string accountId, string depositId, CancellationToken cancellationToken = default); + /// /// Deposits user-defined amount of funds to a fiat account. /// Task> DepositFundsAsync(string accountId, DepositFunds depositFunds, CancellationToken cancellationToken = default); + /// /// Completes a deposit that is created in commit: false state /// @@ -34,42 +36,51 @@ public partial class CoinbaseClient : IDepositsEndpoint private const string deposits = "deposits"; /// - Task> IDepositsEndpoint.ListDepositsAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) + async Task> IDepositsEndpoint.ListDepositsAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, deposits) - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request( + AccountsEndpoint.AppendPathSegmentsRequire(accountId, deposits) + .WithPagination(pagination) + ).GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new PagedResponse(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - Task> IDepositsEndpoint.GetDepositAsync(string accountId, string depositId, CancellationToken cancellationToken) + async Task> IDepositsEndpoint.GetDepositAsync(string accountId, string depositId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, deposits, depositId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, deposits, depositId)) + .GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - Task> IDepositsEndpoint.DepositFundsAsync(string accountId, DepositFunds depositFunds, CancellationToken cancellationToken) + async Task> IDepositsEndpoint.DepositFundsAsync(string accountId, DepositFunds depositFunds, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, deposits) - .WithClient(this) - .PostJsonAsync(depositFunds, cancellationToken) - .ReceiveJson>(); + using var response = Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, deposits)) + .PostJsonAsync(depositFunds, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - Task> IDepositsEndpoint.CommitDepositAsync(string accountId, string depositId, CancellationToken cancellationToken) + async Task> IDepositsEndpoint.CommitDepositAsync(string accountId, string depositId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, deposits, depositId, "commit") - .WithClient(this) - .PostJsonAsync(null, cancellationToken) - .ReceiveJson>(); + using var response = Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, deposits, depositId, "commit")) + .PostJsonAsync(null, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } } } diff --git a/Source/Coinbase/CoinbaseClient.Notifications.cs b/Source/Coinbase/CoinbaseClient.Notifications.cs index de95ffa..08cf5b9 100644 --- a/Source/Coinbase/CoinbaseClient.Notifications.cs +++ b/Source/Coinbase/CoinbaseClient.Notifications.cs @@ -3,16 +3,17 @@ using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { - public interface INotificationsEndpoint { /// /// Lists current user’s payment methods. /// Task> ListNotificationsAsync(PaginationOptions pagination = null, CancellationToken cancellationToken = default); + /// /// Show current user’s payment method. /// @@ -23,22 +24,23 @@ public partial class CoinbaseClient : INotificationsEndpoint { public INotificationsEndpoint Notifications => this; - - Task> INotificationsEndpoint.ListNotificationsAsync(PaginationOptions pagination, CancellationToken cancellationToken) + async Task> INotificationsEndpoint.ListNotificationsAsync(PaginationOptions pagination, CancellationToken cancellationToken) { - return this.NotificationsEndpoint - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request(NotificationsEndpoint.WithPagination(pagination)) + .GetStringAsync(cancellationToken: cancellationToken); + if (string.IsNullOrWhiteSpace(responseBody)) + return new PagedResponse(); + + return JsonConvert.DeserializeObject>(responseBody); } - Task> INotificationsEndpoint.GetNotificationAsync(string notificationId, CancellationToken cancellationToken) + async Task> INotificationsEndpoint.GetNotificationAsync(string notificationId, CancellationToken cancellationToken) { - return this.NotificationsEndpoint - .AppendPathSegmentsRequire(notificationId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } + var responseBody = await Request(NotificationsEndpoint.AppendPathSegmentsRequire(notificationId)) + .GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) return new Response(); + return JsonConvert.DeserializeObject>(responseBody); + } } } diff --git a/Source/Coinbase/CoinbaseClient.OAuth.cs b/Source/Coinbase/CoinbaseClient.OAuth.cs index 8da8821..f536724 100644 --- a/Source/Coinbase/CoinbaseClient.OAuth.cs +++ b/Source/Coinbase/CoinbaseClient.OAuth.cs @@ -224,7 +224,7 @@ async Task TokenExpiredErrorHandler(FlurlCall call) } } - client.Configure(s => s.OnErrorAsync = TokenExpiredErrorHandler); + client.WithSettings(_ => client.OnError(TokenExpiredErrorHandler)); return client; } } diff --git a/Source/Coinbase/CoinbaseClient.PaymentMethods.cs b/Source/Coinbase/CoinbaseClient.PaymentMethods.cs index c057daf..56684ac 100644 --- a/Source/Coinbase/CoinbaseClient.PaymentMethods.cs +++ b/Source/Coinbase/CoinbaseClient.PaymentMethods.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { @@ -23,22 +24,24 @@ public partial class CoinbaseClient : IPaymentMethodsEndpoint { public IPaymentMethodsEndpoint PaymentMethods => this; - - Task> IPaymentMethodsEndpoint.ListPaymentMethodsAsync(PaginationOptions pagination, CancellationToken cancellationToken) + async Task> IPaymentMethodsEndpoint.ListPaymentMethodsAsync(PaginationOptions pagination, CancellationToken cancellationToken) { - return this.PaymentMethodsEndpoint - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request(PaymentMethodsEndpoint.WithPagination(pagination)) + .GetStringAsync(cancellationToken: cancellationToken); + if (string.IsNullOrWhiteSpace(responseBody)) + return new PagedResponse(); + + return JsonConvert.DeserializeObject>(responseBody); } - Task> IPaymentMethodsEndpoint.GetPaymentMethodAsync(string paymentMethodId, CancellationToken cancellationToken) + async Task> IPaymentMethodsEndpoint.GetPaymentMethodAsync(string paymentMethodId, CancellationToken cancellationToken) { - return this.PaymentMethodsEndpoint - .AppendPathSegmentsRequire(paymentMethodId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } + var responseBody = await Request(PaymentMethodsEndpoint.AppendPathSegmentsRequire(paymentMethodId)) + .GetStringAsync(cancellationToken: cancellationToken); + if (string.IsNullOrWhiteSpace(responseBody)) + return new Response(); + return JsonConvert.DeserializeObject>(responseBody); + } } } diff --git a/Source/Coinbase/CoinbaseClient.Sells.cs b/Source/Coinbase/CoinbaseClient.Sells.cs deleted file mode 100644 index f86431b..0000000 --- a/Source/Coinbase/CoinbaseClient.Sells.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Coinbase.Models; -using Flurl.Http; - -namespace Coinbase -{ - public interface ISellsEndpoint - { - /// - /// Lists sells for an account. - /// - Task> ListSellsAsync(string accountId, PaginationOptions pagination = null, CancellationToken cancellationToken = default); - - /// - /// Get an individual sell. - /// - Task> GetSellAsync(string accountId, string sellId, CancellationToken cancellationToken = default); - - /// - /// Sells a user-defined amount of bitcoin, bitcoin cash, litecoin or ethereum. - /// There are two ways to define sell amounts–you can use either the amount or the total parameter: - /// 1.When supplying amount, you’ll get the amount of bitcoin, bitcoin cash, litecoin or ethereum defined. With amount it’s recommended to use BTC or ETH as the currency value, but you can always specify a fiat currency and the amount will be converted to BTC or ETH respectively. - /// 2.When supplying total, your payment method will be credited the total amount and you’ll get the amount in BTC or ETH after fees have been reduced from the subtotal. With total it’s recommended to use the currency of the payment method as the currency parameter, but you can always specify a different currency and it will be converted. - /// Given the price of digital currency depends on the time of the call and amount of the sell, it’s recommended to use the commit: false parameter to create an uncommitted sell to get a quote and then to commit that with a separate request. - ///If you need to query the sell price without locking in the sell, you can use quote: true option. This returns an unsaved sell and unlike commit: false, this sell can’t be completed. This option is useful when you need to show the detailed sell price quote for the user when they are filling a form or similar situation. - /// - Task> PlaceSellOrderAsync(string accountId, PlaceSell placeSell, CancellationToken cancellationToken = default); - - /// - /// Completes a sell that is created in commit: false state. - /// If the exchange rate has changed since the sell was created, this call will fail with the error “The exchange rate updated while you were waiting.The new total is shown below”. - /// The sell’s total will also be updated.You can repeat the /commit call to accept the new values and commit the sell at the new rates. - /// - Task> CommitSellAsync(string accountId, string sellId, CancellationToken cancellationToken = default); - } - - public partial class CoinbaseClient : ISellsEndpoint - { - public ISellsEndpoint Sells => this; - - /// - /// Lists sells for an account. - /// - Task> ISellsEndpoint.ListSellsAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "sells") - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } - - /// - /// Get an individual sell. - /// - Task> ISellsEndpoint.GetSellAsync(string accountId, string sellId, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "sells", sellId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } - - /// - /// Sells a user-defined amount of bitcoin, bitcoin cash, litecoin or ethereum. - /// There are two ways to define sell amounts–you can use either the amount or the total parameter: - /// 1.When supplying amount, you’ll get the amount of bitcoin, bitcoin cash, litecoin or ethereum defined. With amount it’s recommended to use BTC or ETH as the currency value, but you can always specify a fiat currency and the amount will be converted to BTC or ETH respectively. - /// 2.When supplying total, your payment method will be credited the total amount and you’ll get the amount in BTC or ETH after fees have been reduced from the subtotal. With total it’s recommended to use the currency of the payment method as the currency parameter, but you can always specify a different currency and it will be converted. - /// Given the price of digital currency depends on the time of the call and amount of the sell, it’s recommended to use the commit: false parameter to create an uncommitted sell to get a quote and then to commit that with a separate request. - ///If you need to query the sell price without locking in the sell, you can use quote: true option. This returns an unsaved sell and unlike commit: false, this sell can’t be completed. This option is useful when you need to show the detailed sell price quote for the user when they are filling a form or similar situation. - /// - Task> ISellsEndpoint.PlaceSellOrderAsync(string accountId, PlaceSell placeSell, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "sells") - .WithClient(this) - .PostJsonAsync(placeSell, cancellationToken) - .ReceiveJson>(); - } - - /// - /// Completes a sell that is created in commit: false state. - /// If the exchange rate has changed since the sell was created, this call will fail with the error “The exchange rate updated while you were waiting.The new total is shown below”. - /// The sell’s total will also be updated.You can repeat the /commit call to accept the new values and commit the sell at the new rates. - /// - Task> ISellsEndpoint.CommitSellAsync(string accountId, string sellId, CancellationToken cancellationToken) - { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "sells", sellId, "commit") - .WithClient(this) - .PostJsonAsync(null, cancellationToken) - .ReceiveJson>(); - } - - - - } -} diff --git a/Source/Coinbase/CoinbaseClient.Transactions.cs b/Source/Coinbase/CoinbaseClient.Transactions.cs index fb8c208..545e7af 100644 --- a/Source/Coinbase/CoinbaseClient.Transactions.cs +++ b/Source/Coinbase/CoinbaseClient.Transactions.cs @@ -1,58 +1,56 @@ -using System; -using System.Net.Http; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { public interface ITransactionsEndpoint { /// - /// Lists account’s transactions. + /// Lets a user cancel a money request. Money requests can be canceled by the sender or the recipient. /// - Task> ListTransactionsAsync(string accountId, PaginationOptions pagination = null, CancellationToken cancellationToken = default); + Task CancelRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); /// - /// Show an individual transaction for an account. See transaction resource for more information. + /// Lets the recipient of a money request complete the request by sending money to the user who requested the money. This can only be completed by the user to whom the request was made, not the user who sent the request. /// - Task> GetTransactionAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); + Task CompleteRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); /// - /// Send funds to a bitcoin address, bitcoin cash address, litecoin address, ethereum address, or email address. No transaction fees are required for off blockchain bitcoin transactions. - /// It’s recommended to always supply a unique idem field for each transaction.This prevents you from sending the same transaction twice if there has been an unexpected network outage or other issue. - /// When used with OAuth2 authentication, this endpoint requires two factor authentication unless used with wallet:transactions:send:bypass-2fa scope. - ///If the user is able to buy bitcoin, they can send funds from their fiat account using instant exchange feature.Buy fees will be included in the created transaction and the recipient will receive the user defined amount. + /// Show an individual transaction for an account. See transaction resource for more information. /// - Task> SendMoneyAsync(string accountId, CreateTransaction createTransaction, CancellationToken cancellationToken = default); + Task> GetTransactionAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); /// - /// Transfer bitcoin, bitcoin cash, litecoin or ethereum between two of a user’s accounts. Following transfers are allowed: - /// * wallet to wallet - /// * wallet to vault + /// Lists account’s transactions. /// - Task> TransferMoneyAsync(string accountId, CreateTransfer createTransfer, CancellationToken cancellationToken = default); - + Task> ListTransactionsAsync(string accountId, PaginationOptions pagination = null, CancellationToken cancellationToken = default); /// /// Requests money from an email address. /// Task> RequestMoneyAsync(string accountId, RequestMoney requestMoney, CancellationToken cancellationToken = default); /// - /// Lets the recipient of a money request complete the request by sending money to the user who requested the money. This can only be completed by the user to whom the request was made, not the user who sent the request. + /// Lets the user resend a money request. This will notify recipient with a new email. /// - Task CompleteRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); + Task ResendRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); /// - /// Lets the user resend a money request. This will notify recipient with a new email. + /// Send funds to a bitcoin address, bitcoin cash address, litecoin address, ethereum address, or email address. No transaction fees are required for off blockchain bitcoin transactions. + /// It’s recommended to always supply a unique idem field for each transaction.This prevents you from sending the same transaction twice if there has been an unexpected network outage or other issue. + /// When used with OAuth2 authentication, this endpoint requires two factor authentication unless used with wallet:transactions:send:bypass-2fa scope. + ///If the user is able to buy bitcoin, they can send funds from their fiat account using instant exchange feature.Buy fees will be included in the created transaction and the recipient will receive the user defined amount. /// - Task ResendRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); + Task> SendMoneyAsync(string accountId, CreateTransaction createTransaction, CancellationToken cancellationToken = default); /// - /// Lets a user cancel a money request. Money requests can be canceled by the sender or the recipient. + /// Transfer bitcoin, bitcoin cash, litecoin or ethereum between two of a user’s accounts. Following transfers are allowed: + /// * wallet to wallet + /// * wallet to vault /// - Task CancelRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken = default); + Task> TransferMoneyAsync(string accountId, CreateTransfer createTransfer, CancellationToken cancellationToken = default); } @@ -61,103 +59,126 @@ public partial class CoinbaseClient : ITransactionsEndpoint public ITransactionsEndpoint Transactions => this; /// - /// Lists account’s transactions. + /// Lets a user cancel a money request. Money requests can be canceled by the sender or the recipient. /// - Task> ITransactionsEndpoint.ListTransactionsAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) + Task ITransactionsEndpoint.CancelRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions") - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + return Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, "transactions", transactionId)) + .DeleteAsync(cancellationToken: cancellationToken); } /// - /// Show an individual transaction for an account. See transaction resource for more information. + /// Lets the recipient of a money request complete the request by sending money to the user who requested the money. This can only be completed by the user to whom the request was made, not the user who sent the request. /// - Task> ITransactionsEndpoint.GetTransactionAsync(string accountId, string transactionId, CancellationToken cancellationToken) + Task ITransactionsEndpoint.CompleteRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions", transactionId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + return Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "transactions", transactionId, "complete") + ) + .PostJsonAsync(null, cancellationToken: cancellationToken); } /// - /// Send funds to a bitcoin address, bitcoin cash address, litecoin address, ethereum address, or email address. No transaction fees are required for off blockchain bitcoin transactions. - /// It’s recommended to always supply a unique idem field for each transaction.This prevents you from sending the same transaction twice if there has been an unexpected network outage or other issue. - /// When used with OAuth2 authentication, this endpoint requires two factor authentication unless used with wallet:transactions:send:bypass-2fa scope. - ///If the user is able to buy bitcoin, they can send funds from their fiat account using instant exchange feature.Buy fees will be included in the created transaction and the recipient will receive the user defined amount. + /// Show an individual transaction for an account. See transaction resource for more information. /// - Task> ITransactionsEndpoint.SendMoneyAsync(string accountId, CreateTransaction createTransaction, CancellationToken cancellationToken) + async Task> ITransactionsEndpoint.GetTransactionAsync(string accountId, string transactionId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions") - .WithClient(this) - .PostJsonAsync(createTransaction, cancellationToken) - .ReceiveJson>(); - + var responseBody = await Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "transactions", transactionId) + .SetQueryParam("expand", "all") + ) + .GetStringAsync(cancellationToken: cancellationToken); + if (string.IsNullOrWhiteSpace(responseBody)) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - /// Transfer bitcoin, bitcoin cash, litecoin or ethereum between two of a user’s accounts. Following transfers are allowed: - /// * wallet to wallet - /// * wallet to vault + /// Lists account’s transactions. /// - Task> ITransactionsEndpoint.TransferMoneyAsync(string accountId, CreateTransfer createTransfer, CancellationToken cancellationToken) + async Task> ITransactionsEndpoint.ListTransactionsAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions") - .WithClient(this) - .PostJsonAsync(createTransfer, cancellationToken) - .ReceiveJson>(); + var responseBody = await Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "transactions") + .SetQueryParam("expand", "all") + .WithPagination(pagination) + ) + .GetStringAsync(cancellationToken: cancellationToken); + if (string.IsNullOrWhiteSpace(responseBody)) + return new PagedResponse(); + + return JsonConvert.DeserializeObject>(responseBody); } - /// /// Requests money from an email address. /// - Task> ITransactionsEndpoint.RequestMoneyAsync(string accountId, RequestMoney requestMoney, CancellationToken cancellationToken) + async Task> ITransactionsEndpoint.RequestMoneyAsync(string accountId, RequestMoney requestMoney, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions") - .WithClient(this) - .PostJsonAsync(requestMoney, cancellationToken) - .ReceiveJson>(); + using var response = Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "transactions") + ) + .PostJsonAsync(requestMoney, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if (string.IsNullOrWhiteSpace(responseBody)) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - /// Lets the recipient of a money request complete the request by sending money to the user who requested the money. This can only be completed by the user to whom the request was made, not the user who sent the request. + /// Lets the user resend a money request. This will notify recipient with a new email. /// - Task ITransactionsEndpoint.CompleteRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken) + Task ITransactionsEndpoint.ResendRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions", transactionId, "complete") - .WithClient(this) - .PostJsonAsync(null, cancellationToken); + return Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "transactions", transactionId, "resend") + ) + .PostJsonAsync(null, cancellationToken: cancellationToken); } - /// - /// Lets the user resend a money request. This will notify recipient with a new email. + /// Send funds to a bitcoin address, bitcoin cash address, litecoin address, ethereum address, or email address. No transaction fees are required for off blockchain bitcoin transactions. + /// It’s recommended to always supply a unique idem field for each transaction.This prevents you from sending the same transaction twice if there has been an unexpected network outage or other issue. + /// When used with OAuth2 authentication, this endpoint requires two-factor authentication unless used with wallet:transactions:send:bypass-2fa scope. + ///If the user is able to buy bitcoin, they can send funds from their fiat account using instant exchange feature.Buy fees will be included in the created transaction and the recipient will receive the user defined amount. /// - Task ITransactionsEndpoint.ResendRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken) + async Task> ITransactionsEndpoint.SendMoneyAsync(string accountId, CreateTransaction createTransaction, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions", transactionId, "resend") - .WithClient(this) - .PostJsonAsync(null, cancellationToken); + using var response = Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "transactions") + ) + .PostJsonAsync(createTransaction, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if (string.IsNullOrWhiteSpace(responseBody)) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } /// - /// Lets a user cancel a money request. Money requests can be canceled by the sender or the recipient. + /// Transfer bitcoin, bitcoin cash, litecoin or ethereum between two of a user’s accounts. Following transfers are allowed: + /// * wallet to wallet + /// * wallet to vault /// - Task ITransactionsEndpoint.CancelRequestMoneyAsync(string accountId, string transactionId, CancellationToken cancellationToken) + async Task> ITransactionsEndpoint.TransferMoneyAsync(string accountId, CreateTransfer createTransfer, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, "transactions", transactionId) - .WithClient(this) - .DeleteAsync(cancellationToken); + using var response = Request( + AccountsEndpoint + .AppendPathSegmentsRequire(accountId, "transactions") + ) + .PostJsonAsync(createTransfer, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if (string.IsNullOrWhiteSpace(responseBody)) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } - } } diff --git a/Source/Coinbase/CoinbaseClient.Users.cs b/Source/Coinbase/CoinbaseClient.Users.cs deleted file mode 100644 index e03c500..0000000 --- a/Source/Coinbase/CoinbaseClient.Users.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Coinbase.Models; -using Flurl; -using Flurl.Http; - -namespace Coinbase -{ - public interface IUsersEndpoint - { - /// - /// Get any user’s public information with their ID. - /// - Task> GetUserAsync(string userId, CancellationToken cancellationToken = default); - - /// - /// Get current user’s public information. To get user’s email or private information, use permissions wallet:user:email and wallet:user:read. If current request has a wallet:transactions:send scope, then the response will contain a boolean sends_disabled field that indicates if the user’s send functionality has been disabled. - /// - Task> GetCurrentUserAsync(CancellationToken cancellationToken = default); - - /// - /// Get current user’s authorization information including granted scopes and send limits when using OAuth2 authentication. - /// - Task> GetAuthInfoAsync(CancellationToken cancellationToken = default); - - /// - /// Modify current user and their preferences. - /// - Task> UpdateUserAsync(UserUpdate update, CancellationToken cancellationToken = default); - } - - - public partial class CoinbaseClient : IUsersEndpoint - { - public IUsersEndpoint Users => this; - - /// - /// Get any user’s public information with their ID. - /// - Task> IUsersEndpoint.GetUserAsync(string userId, CancellationToken cancellationToken) - { - return this.Config.ApiUrl - .AppendPathSegmentsRequire("users", userId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } - /// - /// Get current user’s public information. To get user’s email or private information, use permissions wallet:user:email and wallet:user:read. If current request has a wallet:transactions:send scope, then the response will contain a boolean sends_disabled field that indicates if the user’s send functionality has been disabled. - /// - Task> IUsersEndpoint.GetCurrentUserAsync(CancellationToken cancellationToken) - { - return this.Config.ApiUrl - .AppendPathSegment("user") - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } - /// - /// Get current user’s authorization information including granted scopes and send limits when using OAuth2 authentication. - /// - Task> IUsersEndpoint.GetAuthInfoAsync(CancellationToken cancellationToken) - { - return this.Config.ApiUrl - .AppendPathSegments("user", "auth") - .WithClient(this) - .GetJsonAsync>(cancellationToken); - } - /// - /// Modify current user and their preferences. - /// - Task> IUsersEndpoint.UpdateUserAsync(UserUpdate update, CancellationToken cancellationToken) - { - return this.Config.ApiUrl - .AppendPathSegment("user") - .WithClient(this) - .PutJsonAsync(update, cancellationToken) - .ReceiveJson>(); - } - } -} diff --git a/Source/Coinbase/CoinbaseClient.Withdrawals.cs b/Source/Coinbase/CoinbaseClient.Withdrawals.cs index d2ea8aa..0aacf8a 100644 --- a/Source/Coinbase/CoinbaseClient.Withdrawals.cs +++ b/Source/Coinbase/CoinbaseClient.Withdrawals.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Coinbase.Models; using Flurl.Http; +using Newtonsoft.Json; namespace Coinbase { @@ -25,48 +26,56 @@ public interface IWithdrawalsEndpoint /// Task> CommitWithdrawalAsync(string accountId, string withdrawalId, CancellationToken cancellationToken = default); } - - + public partial class CoinbaseClient : IWithdrawalsEndpoint { public IWithdrawalsEndpoint Withdrawals => this; private const string withdrawals = "withdrawals"; - Task> IWithdrawalsEndpoint.ListWithdrawalsAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) + async Task> IWithdrawalsEndpoint.ListWithdrawalsAsync(string accountId, PaginationOptions pagination, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, withdrawals) - .WithPagination(pagination) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request( + AccountsEndpoint.AppendPathSegmentsRequire(accountId, withdrawals) + .WithPagination(pagination) + ) + .GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new PagedResponse(); + + return JsonConvert.DeserializeObject>(responseBody); } - Task> IWithdrawalsEndpoint.GetWithdrawalAsync(string accountId, string withdrawalId, CancellationToken cancellationToken) + async Task> IWithdrawalsEndpoint.GetWithdrawalAsync(string accountId, string withdrawalId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, withdrawals, withdrawalId) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + var responseBody = await Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, withdrawals, withdrawalId)) + .GetStringAsync(cancellationToken: cancellationToken); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } - Task> IWithdrawalsEndpoint.WithdrawalFundsAsync(string accountId, WithdrawalFunds withdrawalFunds, CancellationToken cancellationToken) + async Task> IWithdrawalsEndpoint.WithdrawalFundsAsync(string accountId, WithdrawalFunds withdrawalFunds, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, withdrawals) - .WithClient(this) - .PostJsonAsync(withdrawalFunds, cancellationToken) - .ReceiveJson>(); + using var response = Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, withdrawals)) + .PostJsonAsync(withdrawalFunds, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + return JsonConvert.DeserializeObject>(responseBody); } - Task> IWithdrawalsEndpoint.CommitWithdrawalAsync(string accountId, string withdrawalId, CancellationToken cancellationToken) + async Task> IWithdrawalsEndpoint.CommitWithdrawalAsync(string accountId, string withdrawalId, CancellationToken cancellationToken) { - return this.AccountsEndpoint - .AppendPathSegmentsRequire(accountId, withdrawals, withdrawalId, "commit") - .WithClient(this) - .PostJsonAsync(null, cancellationToken) - .ReceiveJson>(); + using var response = Request(AccountsEndpoint.AppendPathSegmentsRequire(accountId, withdrawals, withdrawalId, "commit")) + .PostJsonAsync(null, cancellationToken: cancellationToken); + var responseBody = await response.ReceiveString(); + if( string.IsNullOrWhiteSpace(responseBody) ) + return new Response(); + + return JsonConvert.DeserializeObject>(responseBody); } } } diff --git a/Source/Coinbase/CoinbaseClient.cs b/Source/Coinbase/CoinbaseClient.cs index 076e35f..7cd4597 100644 --- a/Source/Coinbase/CoinbaseClient.cs +++ b/Source/Coinbase/CoinbaseClient.cs @@ -16,20 +16,17 @@ public interface ICoinbaseClient : IFlurlClient { IAccountsEndpoint Accounts { get; } IAddressesEndpoint Addresses { get; } - IBuysEndpoint Buys { get; } IDataEndpoint Data { get; } IDepositsEndpoint Deposits { get; } INotificationsEndpoint Notifications { get; } IPaymentMethodsEndpoint PaymentMethods { get; } - ISellsEndpoint Sells { get; } ITransactionsEndpoint Transactions { get; } - IUsersEndpoint Users { get; } IWithdrawalsEndpoint Withdrawals { get; } } public partial class CoinbaseClient : FlurlClient, ICoinbaseClient { - public const string ApiVersionDate = "2017-08-07"; + public const string ApiVersionDate = "2021-06-05"; public Config Config { get; } @@ -98,32 +95,15 @@ public void EnableFiddlerDebugProxy(string proxyUrl) { var webProxy = new WebProxy(proxyUrl, BypassOnLocal: false); - this.Configure(settings => - { - settings.HttpClientFactory = new DebugProxyFactory(webProxy); - }); - } - - private class DebugProxyFactory : DefaultHttpClientFactory - { - private readonly WebProxy proxy; - - public DebugProxyFactory(WebProxy proxy) - { - this.proxy = proxy; - } - - public override HttpMessageHandler CreateMessageHandler() - { - return new HttpClientHandler + FlurlHttp.Clients.WithDefaults(builder => builder.ConfigureInnerHandler( + hch => { - Proxy = this.proxy, - UseProxy = true - }; - } + hch.Proxy = new WebProxy(proxyUrl, BypassOnLocal: false); + hch.UseProxy = true; + } + )); } - /// /// Get the next page of data given the current paginated response. /// @@ -158,12 +138,10 @@ public Task> GetNextPageAsync(PagedResponse currentPage, protected internal Task> GetPageAsync(string pageUrl, CancellationToken cancellationToken = default) { pageUrl = pageUrl.Remove(0, 4); - return (this.Config.ApiUrl + pageUrl) - .WithClient(this) - .GetJsonAsync>(cancellationToken); + return this.Request(Config.ApiUrl + pageUrl) + .GetJsonAsync>(cancellationToken: cancellationToken); } - /// /// Captures the low-level from a /// underlying request. Useful in advanced scenarios where you @@ -179,27 +157,10 @@ public CoinbaseClient HoistResponse(out Func responseGetter) { IFlurlResponse msg = null; - void CaptureResponse(FlurlCall http) - { - msg = http.Response; - - this.Configure(cf => - { - // Remove Action from Invocation list - // to avoid memory leak from further calls to the same - // client object. - cf.AfterCall -= CaptureResponse; - }); - } - - this.Configure(cf => - { - cf.AfterCall += CaptureResponse; - }); + this.WithSettings(_ => this.AfterCall(call => msg = call.Response)); responseGetter = () => msg; return this; } - } } diff --git a/Source/Coinbase/Config.cs b/Source/Coinbase/Config.cs index bf0338c..16c9041 100644 --- a/Source/Coinbase/Config.cs +++ b/Source/Coinbase/Config.cs @@ -42,17 +42,12 @@ internal override void EnsureValid() protected internal override void Configure(CoinbaseClient client) { - client.Configure(settings => UseOAuth(settings, client)); + client.WithSettings(_ => UseOAuth(client)); } - private void UseOAuth(ClientFlurlHttpSettings settings, CoinbaseClient client) + private void UseOAuth(CoinbaseClient client) { - async Task ApplyAuthorization(FlurlCall call) - { - call.Request.WithOAuthBearerToken(this.AccessToken); - } - - settings.BeforeCallAsync = ApplyAuthorization; + client.BeforeCall(call => call.Request.WithOAuthBearerToken(AccessToken)); } } @@ -68,10 +63,10 @@ internal override void EnsureValid() protected internal override void Configure(CoinbaseClient client) { - client.Configure(settings => ApiKeyAuth(settings, client)); + client.WithSettings(_ => ApiKeyAuth(client)); } - private void ApiKeyAuth(ClientFlurlHttpSettings settings, CoinbaseClient client) + private void ApiKeyAuth(CoinbaseClient client) { async Task SetHeaders(FlurlCall http) { @@ -98,7 +93,7 @@ async Task SetHeaders(FlurlCall http) .WithHeader(HeaderNames.AccessTimestamp, timestamp); } - settings.BeforeCallAsync = SetHeaders; + client.BeforeCall(SetHeaders); } } } diff --git a/Source/Coinbase/Models/JsonResponse.cs b/Source/Coinbase/Models/JsonResponse.cs index 524e064..3e7e75f 100644 --- a/Source/Coinbase/Models/JsonResponse.cs +++ b/Source/Coinbase/Models/JsonResponse.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; +using System.ComponentModel; namespace Coinbase.Models { @@ -128,7 +129,7 @@ public class Pagination : Json public int Limit { get; set; } - [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("order"), JsonConverter(typeof(StringEnumConverter))] public SortOrder Order { get; set; } [JsonProperty("previous_uri")] @@ -141,7 +142,10 @@ public class Pagination : Json public enum SortOrder { + [Description("desc"), EnumMember(Value = "desc")] Desc, + + [Description("asc"), EnumMember(Value = "asc")] Asc } diff --git a/Source/Coinbase/Models/Objects.cs b/Source/Coinbase/Models/Objects.cs index fdacbca..a73c2e5 100644 --- a/Source/Coinbase/Models/Objects.cs +++ b/Source/Coinbase/Models/Objects.cs @@ -167,10 +167,21 @@ public partial class Transaction : Entity public partial class Transaction { [JsonProperty("buy")] - public Entity Buy { get; set; } - } + public Buy Buy { get; set; } + + [JsonProperty("sell")] + public Sell Sell { get; set; } + public bool ShouldSerializeBuy() + { + return "buy".Equals(Type); + } + public bool ShouldSerializeSell() + { + return "sell".Equals(Type); + } + } public partial class Buy : Entity { diff --git a/Source/Examples/Examples.csproj b/Source/Examples/Examples.csproj index 1ce760c..83d45b2 100644 --- a/Source/Examples/Examples.csproj +++ b/Source/Examples/Examples.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.1 + net7.0