diff --git a/.github/workflows/station.yml b/.github/workflows/station.yml new file mode 100644 index 0000000..acffcfe --- /dev/null +++ b/.github/workflows/station.yml @@ -0,0 +1,66 @@ +name: API + +on: + push: + branches: [ main, dev ] + paths: + - 'TrainStation/**' + - '.github/workflows/station.yml' + pull_request: + branches: [ main, dev ] + paths: + - 'TrainStation/**' + - '.github/workflows/station.yml' + release: + types: [published, created] + +env: + DOCKER_IMAGE: trainprotocol/station + DOTNET_VERSION: 9 + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Format version + id: format_version + run: | + commitHash=${GITHUB_SHA:0:7} + ts=$(date +%s) + version=$commitHash-$ts + echo "VERSION=$version" >> $GITHUB_ENV + + - name: Sanitize branch name + id: sanitize_branch_name + run: | + sanitized_ref_name=$(echo "${GITHUB_REF_NAME}" | sed 's/[\/.]/-/g') + echo "SANITIZED_REF_NAME=$sanitized_ref_name" >> $GITHUB_ENV + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: TrainStation/Dockerfile + push: ${{github.ref_name == 'main' || github.ref_name == 'dev'}} + build-args: | + DOTNET_VERSION=${{ env.DOTNET_VERSION }} + tags: | + ${{ env.DOCKER_IMAGE }}:${{ env.SANITIZED_REF_NAME }}-${{ env.VERSION }} + ${{ env.DOCKER_IMAGE }}:${{ env.SANITIZED_REF_NAME }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/TrainStation.sln b/TrainStation.sln index e1cdf5a..e4de273 100644 --- a/TrainStation.sln +++ b/TrainStation.sln @@ -5,6 +5,11 @@ VisualStudioVersion = 17.13.35825.156 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "TrainStation\API.csproj", "{2CBBA91C-0E98-44EC-8417-5C2E686F9431}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_config", "_config", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" + ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/TrainStation/API.csproj b/TrainStation/API.csproj index 9a08a1a..a1bc221 100644 --- a/TrainStation/API.csproj +++ b/TrainStation/API.csproj @@ -12,17 +12,17 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - - - - + diff --git a/TrainStation/Client/QuoteWithSolverDto.cs b/TrainStation/Client/QuoteWithSolverDto.cs new file mode 100644 index 0000000..e50f842 --- /dev/null +++ b/TrainStation/Client/QuoteWithSolverDto.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Train.Station.Client; + +public partial class QuoteWithSolverDto +{ + [JsonProperty("solverName", NullValueHandling = NullValueHandling.Ignore)] + public string SolverName { get; set; } +} \ No newline at end of file diff --git a/TrainStation/Client/TrainSolverApiClient.cs b/TrainStation/Client/TrainSolverApiClient.cs index 6b96534..8fa77e1 100644 --- a/TrainStation/Client/TrainSolverApiClient.cs +++ b/TrainStation/Client/TrainSolverApiClient.cs @@ -28,11 +28,6 @@ namespace Train.Station.Client public partial interface ITrainSolverApiClient { - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - System.Threading.Tasks.Task NetworksAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. @@ -41,32 +36,17 @@ public partial interface ITrainSolverApiClient /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. - System.Threading.Tasks.Task SourcesAsync(string destinationNetwork = null, string destinationToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - System.Threading.Tasks.Task DestinationsAsync(string sourceNetwork = null, string sourceToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + System.Threading.Tasks.Task QuoteAsync(string amount, string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. - System.Threading.Tasks.Task LimitsAsync(string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + System.Threading.Tasks.Task SwapsAsync(string commitId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. - System.Threading.Tasks.Task QuoteAsync(double amount, string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - System.Threading.Tasks.Task SwapsAsync(System.Collections.Generic.IEnumerable addresses = null, int? page = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - System.Threading.Tasks.Task Swaps2Async(string commitId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + System.Threading.Tasks.Task BuildAsync(PrepareTransactionRequest body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK @@ -128,77 +108,6 @@ public string BaseUrl partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task NetworksAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "api/v1/networks" - urlBuilder_.Append("api/v1/networks"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. @@ -273,258 +182,7 @@ public string BaseUrl /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SourcesAsync(string destinationNetwork = null, string destinationToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "api/v1/sources" - urlBuilder_.Append("api/v1/sources"); - urlBuilder_.Append('?'); - if (destinationNetwork != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("destinationNetwork")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationNetwork, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (destinationToken != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("destinationToken")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationToken, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task DestinationsAsync(string sourceNetwork = null, string sourceToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "api/v1/destinations" - urlBuilder_.Append("api/v1/destinations"); - urlBuilder_.Append('?'); - if (sourceNetwork != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("sourceNetwork")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sourceNetwork, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (sourceToken != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("sourceToken")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sourceToken, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task LimitsAsync(string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) - { - if (sourceNetwork == null) - throw new System.ArgumentNullException("sourceNetwork"); - - if (sourceToken == null) - throw new System.ArgumentNullException("sourceToken"); - - if (destinationNetwork == null) - throw new System.ArgumentNullException("destinationNetwork"); - - if (destinationToken == null) - throw new System.ArgumentNullException("destinationToken"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "api/v1/limits" - urlBuilder_.Append("api/v1/limits"); - urlBuilder_.Append('?'); - urlBuilder_.Append(System.Uri.EscapeDataString("SourceNetwork")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sourceNetwork, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Append(System.Uri.EscapeDataString("SourceToken")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sourceToken, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Append(System.Uri.EscapeDataString("DestinationNetwork")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationNetwork, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Append(System.Uri.EscapeDataString("DestinationToken")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationToken, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task QuoteAsync(double amount, string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + public virtual async System.Threading.Tasks.Task QuoteAsync(string amount, string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { if (amount == null) throw new System.ArgumentNullException("amount"); @@ -587,7 +245,7 @@ public string BaseUrl var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -617,8 +275,11 @@ public string BaseUrl /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SwapsAsync(System.Collections.Generic.IEnumerable addresses = null, int? page = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + public virtual async System.Threading.Tasks.Task SwapsAsync(string commitId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { + if (commitId == null) + throw new System.ArgumentNullException("commitId"); + var client_ = _httpClient; var disposeClient_ = false; try @@ -630,18 +291,9 @@ public string BaseUrl var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "api/v1/swaps" - urlBuilder_.Append("api/v1/swaps"); - urlBuilder_.Append('?'); - if (addresses != null) - { - foreach (var item_ in addresses) { urlBuilder_.Append(System.Uri.EscapeDataString("addresses")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } - } - if (page != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; + // Operation Path: "api/v1/swaps/{commitId}" + urlBuilder_.Append("api/v1/swaps/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(commitId, System.Globalization.CultureInfo.InvariantCulture))); PrepareRequest(client_, request_, urlBuilder_); @@ -698,10 +350,10 @@ public string BaseUrl /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// OK /// A server side error occurred. - public virtual async System.Threading.Tasks.Task Swaps2Async(string commitId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + public virtual async System.Threading.Tasks.Task BuildAsync(PrepareTransactionRequest body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { - if (commitId == null) - throw new System.ArgumentNullException("commitId"); + if (body == null) + throw new System.ArgumentNullException("body"); var client_ = _httpClient; var disposeClient_ = false; @@ -709,14 +361,17 @@ public string BaseUrl { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Method = new System.Net.Http.HttpMethod("GET"); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "api/v1/swaps/{commitId}" - urlBuilder_.Append("api/v1/swaps/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(commitId, System.Globalization.CultureInfo.InvariantCulture))); + // Operation Path: "api/v1/transactions/build" + urlBuilder_.Append("api/v1/transactions/build"); PrepareRequest(client_, request_, urlBuilder_); @@ -743,7 +398,7 @@ public string BaseUrl var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1030,18 +685,6 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu } } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum AccountType - { - - [System.Runtime.Serialization.EnumMember(Value = @"LP")] - LP = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"Charging")] - Charging = 1, - - } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class AddLockSignatureModel { @@ -1068,9 +711,6 @@ public partial class AddLockSignatureModel [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiError { - [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Code { get; set; } - [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } @@ -1085,46 +725,35 @@ public partial class ApiResponse } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ApiResponseLimitDto - { - [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public ApiError Error { get; set; } - - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public LimitDto Data { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ApiResponseListDetailedNetworkDto + public partial class ApiResponseListRouteDto { [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public ApiError Error { get; set; } [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Data { get; set; } + public System.Collections.Generic.ICollection Data { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ApiResponseListRouteDto + public partial class ApiResponsePrepareTransactionDto { [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public ApiError Error { get; set; } - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Data { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public PrepareTransactionDto Data { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ApiResponseQuoteDto + public partial class ApiResponseQuoteWithSolverDto { [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public ApiError Error { get; set; } [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public QuoteDto Data { get; set; } + public QuoteWithSolverDto Data { get; set; } } @@ -1140,211 +769,115 @@ public partial class ApiResponseSwapDto } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum ContarctType - { - - [System.Runtime.Serialization.EnumMember(Value = @"HTLCNativeContractAddress")] - HTLCNativeContractAddress = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"HTLCTokenContractAddress")] - HTLCTokenContractAddress = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"GasPriceOracleContract")] - GasPriceOracleContract = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"EvmMultiCallContract")] - EvmMultiCallContract = 3, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ContractDto - { - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public ContarctType Type { get; set; } - - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Address { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DetailedNetworkDto + public partial class NetworkDto { [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Name { get; set; } - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string ChainId { get; set; } [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public NetworkType Type { get; set; } - [Newtonsoft.Json.JsonProperty("displayName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string DisplayName { get; set; } - - [Newtonsoft.Json.JsonProperty("logo", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Logo { get; set; } - - [Newtonsoft.Json.JsonProperty("transactionExplorerTemplate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TransactionExplorerTemplate { get; set; } - - [Newtonsoft.Json.JsonProperty("accountExplorerTemplate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string AccountExplorerTemplate { get; set; } - - [Newtonsoft.Json.JsonProperty("nativeToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public DetailedTokenDto NativeToken { get; set; } - - [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Tokens { get; set; } - - [Newtonsoft.Json.JsonProperty("nodes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Nodes { get; set; } - - [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Contracts { get; set; } - - [Newtonsoft.Json.JsonProperty("managedAccounts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection ManagedAccounts { get; set; } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DetailedTokenDto + public enum NetworkType { - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Symbol { get; set; } - [Newtonsoft.Json.JsonProperty("contract", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Contract { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"EVM")] + EVM = 0, - [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int Decimals { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"Solana")] + Solana = 1, - [Newtonsoft.Json.JsonProperty("precision", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int Precision { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"Starknet")] + Starknet = 2, - [Newtonsoft.Json.JsonProperty("logo", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Logo { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"Fuel")] + Fuel = 3, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class LimitDto + public partial class PrepareTransactionDto { - [Newtonsoft.Json.JsonProperty("minAmountInUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double MinAmountInUsd { get; set; } - - [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double MinAmount { get; set; } + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ToAddress { get; set; } - [Newtonsoft.Json.JsonProperty("maxAmountInUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double MaxAmountInUsd { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Data { get; set; } - [Newtonsoft.Json.JsonProperty("maxAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double MaxAmount { get; set; } + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Asset { get; set; } - } + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ManagedAccountDto - { - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Address { get; set; } + [Newtonsoft.Json.JsonProperty("callDataAsset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CallDataAsset { get; set; } - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public AccountType Type { get; set; } + [Newtonsoft.Json.JsonProperty("callDataAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CallDataAmount { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class NetworkDto + public partial class PrepareTransactionRequest { - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } - - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ChainId { get; set; } - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public NetworkType Type { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum NetworkType - { - - [System.Runtime.Serialization.EnumMember(Value = @"EVM")] - EVM = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"Solana")] - Solana = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"Starknet")] - Starknet = 2, - - } + public TransactionType Type { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class NodeDto - { - [Newtonsoft.Json.JsonProperty("url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Url { get; set; } + [Newtonsoft.Json.JsonProperty("args", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Args { get; set; } - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public NodeType Type { get; set; } + [Newtonsoft.Json.JsonProperty("networkName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string NetworkName { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum NodeType + public partial class QuoteWithSolverDto { + [Newtonsoft.Json.JsonProperty("totalFee", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TotalFee { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"Primary")] - Primary = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"DepositTracking")] - DepositTracking = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"Public")] - Public = 2, + [Newtonsoft.Json.JsonProperty("totalServiceFee", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TotalServiceFee { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"Secondary")] - Secondary = 3, + [Newtonsoft.Json.JsonProperty("totalExpenseFee", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TotalExpenseFee { get; set; } - } + [Newtonsoft.Json.JsonProperty("receiveAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ReceiveAmount { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class QuoteDto - { - [Newtonsoft.Json.JsonProperty("totalFee", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double TotalFee { get; set; } + [Newtonsoft.Json.JsonProperty("sourceSolverAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SourceSolverAddress { get; set; } - [Newtonsoft.Json.JsonProperty("totalFeeInUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double TotalFeeInUsd { get; set; } + [Newtonsoft.Json.JsonProperty("destinationSolverAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DestinationSolverAddress { get; set; } - [Newtonsoft.Json.JsonProperty("receiveAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double ReceiveAmount { get; set; } + [Newtonsoft.Json.JsonProperty("sourceContractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SourceContractAddress { get; set; } - [Newtonsoft.Json.JsonProperty("receiveAmountInUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double ReceiveAmountInUsd { get; set; } + [Newtonsoft.Json.JsonProperty("destinationContractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DestinationContractAddress { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RouteDto { - [Newtonsoft.Json.JsonProperty("source", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TokenNetworkDto Source { get; set; } + [Newtonsoft.Json.JsonProperty("source", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenNetworkDto Source { get; set; } = new TokenNetworkDto(); - [Newtonsoft.Json.JsonProperty("destionation", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TokenNetworkDto Destionation { get; set; } + [Newtonsoft.Json.JsonProperty("destination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenNetworkDto Destination { get; set; } = new TokenNetworkDto(); } @@ -1354,32 +887,35 @@ public partial class SwapDto [Newtonsoft.Json.JsonProperty("commitId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string CommitId { get; set; } - [Newtonsoft.Json.JsonProperty("sourceNetwork", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SourceNetwork { get; set; } + [Newtonsoft.Json.JsonProperty("hashlock", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Hashlock { get; set; } - [Newtonsoft.Json.JsonProperty("sourceToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SourceToken { get; set; } + [Newtonsoft.Json.JsonProperty("source", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TokenNetworkDto Source { get; set; } [Newtonsoft.Json.JsonProperty("sourceAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double SourceAmount { get; set; } + public string SourceAmount { get; set; } [Newtonsoft.Json.JsonProperty("sourceAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string SourceAddress { get; set; } - [Newtonsoft.Json.JsonProperty("destinationNetwork", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string DestinationNetwork { get; set; } + [Newtonsoft.Json.JsonProperty("sourceContractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SourceContractAddress { get; set; } - [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string DestinationToken { get; set; } + [Newtonsoft.Json.JsonProperty("destination", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TokenNetworkDto Destination { get; set; } [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double DestinationAmount { get; set; } + public string DestinationAmount { get; set; } [Newtonsoft.Json.JsonProperty("destinationAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string DestinationAddress { get; set; } + [Newtonsoft.Json.JsonProperty("destinationContractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DestinationContractAddress { get; set; } + [Newtonsoft.Json.JsonProperty("feeAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double FeeAmount { get; set; } + public string FeeAmount { get; set; } [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection Transactions { get; set; } @@ -1398,9 +934,6 @@ public partial class TokenDto [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public int Decimals { get; set; } - [Newtonsoft.Json.JsonProperty("precision", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int Precision { get; set; } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")] diff --git a/TrainStation/Dockerfile b/TrainStation/Dockerfile new file mode 100644 index 0000000..3392422 --- /dev/null +++ b/TrainStation/Dockerfile @@ -0,0 +1,19 @@ +ARG DOTNET_VERSION + +FROM mcr.microsoft.com/dotnet/aspnet:${DOTNET_VERSION}.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}.0 AS build +WORKDIR /build + +COPY TrainStation/ TrainStation/ + +FROM build AS publish +RUN dotnet publish "TrainStation/API.csproj" -c Release -o /app/publish + +FROM base AS final + +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Train.Station.API.dll"] +EXPOSE 8080 \ No newline at end of file diff --git a/TrainStation/Endpoints/StationEndpoints.cs b/TrainStation/Endpoints/StationEndpoints.cs index a1ac488..6fad2a3 100644 --- a/TrainStation/Endpoints/StationEndpoints.cs +++ b/TrainStation/Endpoints/StationEndpoints.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using System.Text; using Train.Station.API.Models; using Train.Station.API.Services; using Train.Station.Client; @@ -17,120 +18,113 @@ public static RouteGroupBuilder MapEndpoints(this RouteGroupBuilder group) group.MapGet("/routes", GetAllRoutesAsync) .Produces>(); - //group.MapGet("/quote", GetQuoteAsync) - // .Produces(); + group.MapGet("/quote", GetQuoteAsync) + .Produces(); - //group.MapGet("/{solver}/swaps", GetAllSwapsAsync) - // .Produces(); + group.MapGet("/{solver}/swaps/{commitId}", GetSwapAsync) + .Produces(); - //group.MapGet("/{solver}/swaps/{commitId}", GetSwapAsync) - // .Produces(); - - //group.MapPost("/{solver}/swaps/{commitId}/addLockSig", AddLockSigAsync) - // .Produces(); + group.MapPost("/{solver}/swaps/{commitId}/addLockSig", AddLockSigAsync) + .Produces(); return group; } + private static async Task GetSwapAsync( + HttpContext httpContext, + SolverCache solverCache, + [FromRoute] string solver, + [FromRoute] string commitId, + IHttpClientFactory httpClientFactory) + { + if (!solverCache.GetAll().TryGetValue(solver, out var solverObj)) + { + return Results.NotFound(); + } + + var httpClient = httpClientFactory.CreateClient(solver); + var trainSilverClient = new TrainSolverApiClient( + solverObj.Url.ToString(), httpClient); - //private static async Task GetSwapRouteLimitsAsync( - // HttpContext httpContext, - // IRouteService routeService, - // [AsParameters] GetRouteLimitsQueryParams queryParams) - //{ - // var limit = await routeService.GetLimitAsync( - // new() - // { - // SourceNetwork = queryParams.SourceNetwork!, - // SourceToken = queryParams.SourceToken!, - // DestinationNetwork = queryParams.DestinationNetwork!, - // DestinationToken = queryParams.DestinationToken!, - // }); - - // if (limit == null) - // { - // return Results.NotFound(new ApiResponse() - // { - // Error = new ApiError() - // { - // Code = "LIMIT_NOT_FOUND", - // Message = "Limit not found", - // } - // }); - // } - - // return Results.Ok(new ApiResponse { Data = limit }); - //} + var swap = await trainSilverClient.SwapsAsync(commitId); - private static async Task GetNetworksAsync( + return Results.Ok(swap); + } + + private static async Task AddLockSigAsync( HttpContext httpContext, - NetworkConfigurationCache networkConfigurationCache) + SolverCache solverCache, + [FromRoute] string solver, + [FromRoute] string commitId, + IHttpClientFactory httpClientFactory, + AddLockSignatureModel addLock) { - var networks = networkConfigurationCache.GetAll(); + if (!solverCache.GetAll().TryGetValue(solver, out var solverObj)) + { + return Results.NotFound(); + } + + var httpClient = httpClientFactory.CreateClient(solver); + var trainSilverClient = new TrainSolverApiClient( + solverObj.Url.ToString(), httpClient); - return Results.Ok(networks); + var swap = await trainSilverClient.SwapsAsync(commitId); + + if (swap == null) + { + return Results.NotFound(); + } + + var lockSig = await trainSilverClient.AddLockSigAsync(commitId, addLock); + return Results.Ok(lockSig); } - //private static async Task GetAllSourcesAsync( - // IRouteService routeService, - // INetworkRepository networkRepository, - // [FromQuery] string? destinationNetwork, - // [FromQuery] string? destinationToken) - //{ - // var sources = await routeService.GetSourcesAsync( - // networkName: destinationNetwork, - // token: destinationToken); - - // if (sources == null || !sources.Any()) - // { - // return Results.NotFound(new ApiResponse() - // { - // Error = new ApiError() - // { - // Code = "REACHABLE_POINTS_NOT_FOUND", - // Message = "No reachable points found", - // } - // }); - // } - - // return Results.Ok(new ApiResponseListDetailedNetworkDto { Data = sources }); - //} + private static async Task GetNetworksAsync( + NetworkConfigurationCache networkConfigurationCache) + { + return Results.Ok(networkConfigurationCache.GetAll()); + } private static async Task GetAllRoutesAsync( RouteCache routeCache) { - var routes = routeCache.GetAll(); + var routes = await routeCache.GetAllAsync(); return Results.Ok(routes); } - //private static async Task GetQuoteAsync( - // IRouteService routeService, - // HttpContext httpContext, - // [AsParameters] GetQuoteQueryParams queryParams) - //{ - // var quoteRequest = new QuoteRequest - // { - // SourceNetwork = queryParams.SourceNetwork!, - // SourceToken = queryParams.SourceToken!, - // DestinationNetwork = queryParams.DestinationNetwork!, - // DestinationToken = queryParams.DestinationToken!, - // Amount = queryParams.Amount!.Value, - // }; - - // var quote = await routeService.GetValidatedQuoteAsync(quoteRequest); - - // if (quote == null) - // { - // return Results.NotFound(new ApiResponse() - // { - // Error = new ApiError() - // { - // Code = "QUOTE_NOT_FOUND", - // Message = "Quote not found", - // } - // }); - // } - - // return Results.Ok(new ApiResponseQuoteDto { Data = quote }); - //} + private static async Task GetQuoteAsync( + RouteCache routeCache, + SolverCache solverCache, + IHttpClientFactory httpClientFactory, + [FromQuery] string sourceNetwork, + [FromQuery] string sourceToken, + [FromQuery] string destinationNetwork, + [FromQuery] string destinationToken, + [FromQuery] string amount) + { + var solvers = await routeCache.GetSolversByRouteAsync( + sourceNetwork, + sourceToken, + destinationNetwork, + destinationToken); + + var solverName = solvers.First(); + + var solverInfo = solverCache.GetAll()[solverName]; + var httpClient = httpClientFactory.CreateClient(solverName); + + var trainSilverClient = new TrainSolverApiClient( + solverInfo.Url.ToString(), httpClient); + + var quote = await trainSilverClient.QuoteAsync( + amount, + sourceNetwork, + sourceToken, + destinationNetwork, + destinationToken); + + quote.Data.SolverName = solverName; + + return Results.Ok(quote); + } } diff --git a/TrainStation/Models/NetworkConfiguration.cs b/TrainStation/Models/NetworkConfiguration.cs index 05ecd77..41e1b9a 100644 --- a/TrainStation/Models/NetworkConfiguration.cs +++ b/TrainStation/Models/NetworkConfiguration.cs @@ -12,9 +12,11 @@ public class NetworkConfiguration public string AccountExplorerTemplate { get; set; } = null!; - public string NativeSymbol { get; set; } = null!; + public string NativeTokenSymbol { get; set; } = null!; - public int Decimals { get; set; } + public int NativeTokenDecimals { get; set; } public string RpcUrl { get; set; } = null!; + + public string Type { get; set; } = null!; } diff --git a/TrainStation/Options/TrainStationOptions.cs b/TrainStation/Options/TrainStationOptions.cs new file mode 100644 index 0000000..3e5a36e --- /dev/null +++ b/TrainStation/Options/TrainStationOptions.cs @@ -0,0 +1,10 @@ +namespace Train.Station.API.Options; + +public class TrainStationOptions +{ + public const string SectionName = "TrainStation"; + + public string RedisConnectionString { get; set; } = null!; + + public int RedisDatabaseIndex { get; set; } = 4; +} diff --git a/TrainStation/Program.cs b/TrainStation/Program.cs index 18d1f63..bb44e10 100644 --- a/TrainStation/Program.cs +++ b/TrainStation/Program.cs @@ -1,7 +1,10 @@ +using Microsoft.Extensions.Options; +using StackExchange.Redis; using System.Text.Json.Serialization; using System.Threading.RateLimiting; using Train.Station.API.Endpoints; using Train.Station.API.Extensions; +using Train.Station.API.Options; using Train.Station.API.Services; var builder = WebApplication.CreateBuilder(args); @@ -37,6 +40,17 @@ options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); +var options = new TrainStationOptions(); +configuration.GetSection(TrainStationOptions.SectionName).Bind(options); + +builder.Services.AddSingleton( + ConnectionMultiplexer.Connect(options.RedisConnectionString)); + +builder.Services.AddTransient(sp => sp + .GetRequiredService() + .GetDatabase(options.RedisDatabaseIndex)); + + builder.Services.AddHttpClient(); builder.Services.AddMemoryCache(); builder.Services.AddSingleton(); @@ -67,6 +81,9 @@ var app = builder.Build(); +app.UseRateLimiter(); +app.UseCors(); + app.MapGroup("/api") .MapGet("/health", () => Results.Ok()) .WithTags("System") @@ -85,7 +102,5 @@ c.DisplayRequestDuration(); }); -app.UseRateLimiter(); -app.UseCors(); await app.RunAsync(); diff --git a/TrainStation/Services/JsonFileCache.cs b/TrainStation/Services/JsonFileCache.cs new file mode 100644 index 0000000..df8ec80 --- /dev/null +++ b/TrainStation/Services/JsonFileCache.cs @@ -0,0 +1,28 @@ +using System.Text.Json; + +namespace Train.Station.API.Services; + +public abstract class JsonFileCache +{ + protected TCollection Items { get; } + + protected JsonFileCache( + IWebHostEnvironment env, + string fileName, + Func, TCollection> transform) + { + var filePath = Path.Combine(env.ContentRootPath, fileName); + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"Could not find {fileName}", filePath); + } + + var json = File.ReadAllText(filePath); + var deserialized = JsonSerializer.Deserialize>(json, new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }) ?? throw new InvalidOperationException($"Deserialization of {fileName} returned null."); + + Items = transform(deserialized); + } +} \ No newline at end of file diff --git a/TrainStation/Services/NetworkConfigurationCache.cs b/TrainStation/Services/NetworkConfigurationCache.cs index 5102b1c..d1a84c0 100644 --- a/TrainStation/Services/NetworkConfigurationCache.cs +++ b/TrainStation/Services/NetworkConfigurationCache.cs @@ -3,24 +3,10 @@ namespace Train.Station.API.Services; -public class NetworkConfigurationCache +public class NetworkConfigurationCache( + IWebHostEnvironment env) + : JsonFileCache, NetworkConfiguration>( + env, "networks.json", list => list) { - private readonly List _networks; - - public NetworkConfigurationCache(IWebHostEnvironment env) - { - var filePath = Path.Combine(env.ContentRootPath, "networks.json"); - if (!File.Exists(filePath)) - { - throw new FileNotFoundException("Could not find networks.json", filePath); - } - - var json = File.ReadAllText(filePath); - _networks = JsonSerializer.Deserialize>(json, new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true - }) ?? new List(); - } - - public IReadOnlyList GetAll() => _networks; + public IReadOnlyList GetAll() => Items; } \ No newline at end of file diff --git a/TrainStation/Services/RouteCache.cs b/TrainStation/Services/RouteCache.cs index 26876de..fc8ec3f 100644 --- a/TrainStation/Services/RouteCache.cs +++ b/TrainStation/Services/RouteCache.cs @@ -1,132 +1,88 @@ -using Microsoft.Extensions.Caching.Memory; -using System.Collections.Concurrent; +using Microsoft.AspNetCore.DataProtection.KeyManagement; +using Microsoft.AspNetCore.Routing; +using StackExchange.Redis; +using System.Text.Json; +using System.Text.Json.Nodes; using Train.Station.Client; namespace Train.Station.API.Services; -public class RouteCache(IMemoryCache cache, NetworkConfigurationCache networkConfigCache) +public class RouteCache( + IDatabase cache, + IConnectionMultiplexer connectionMultiplexer, + NetworkConfigurationCache networkConfigCache) { - private readonly ConcurrentDictionary> _routeToLps = new(); private readonly HashSet _validNetworkNames = networkConfigCache .GetAll() .Select(n => n.Name) .ToHashSet(StringComparer.OrdinalIgnoreCase); - public void AddOrUpdateRoute(string lpId, IEnumerable routes, TimeSpan ttl) + public async Task AddOrUpdateRouteAsync(string lpId, IEnumerable routes, TimeSpan ttl) { foreach (var route in routes) { if (!_validNetworkNames.Contains(route.Source.Network.Name) || - !_validNetworkNames.Contains(route.Destionation.Network.Name)) + !_validNetworkNames.Contains(route.Destination.Network.Name)) { continue; } - string key = GetRouteKey(route); + await cache.SortedSetAddAsync( + "ROUTES", + JsonSerializer.Serialize(route), + DateTimeOffset.UtcNow.ToUnixTimeSeconds()); - var cacheEntryOptions = new MemoryCacheEntryOptions - { - AbsoluteExpirationRelativeToNow = ttl, - PostEvictionCallbacks = - { - new PostEvictionCallbackRegistration - { - EvictionCallback = (evictedKey, value, reason, state) => - { - var routeKey = (string)evictedKey; - - if (_routeToLps.TryGetValue(routeKey, out var lpSet)) - { - lpSet.TryRemove(lpId, out _); - - if (lpSet.IsEmpty) - _routeToLps.TryRemove(routeKey, out _); - } - } - } - } - }; - - cache.Set(key, route, cacheEntryOptions); - - if (_routeToLps.TryGetValue(key, out var lpMap)) - { - lpMap[lpId] = true; - } - else - { - _routeToLps[key] = new ConcurrentDictionary( - [new KeyValuePair(lpId, true)]); - } + await cache.SetAddAsync( + GetRouteKey("SOLVERS", route), + new RedisValue(lpId)); } } - public HashSet GetAll() + public async Task> GetAllAsync() { - var routes = new HashSet(); + var now = DateTimeOffset.UtcNow; + var start = now.AddMinutes(-5).ToUnixTimeSeconds(); + var end = now.ToUnixTimeSeconds(); - foreach (var key in _routeToLps.Keys) - { - if (cache.TryGetValue(key, out var route)) - { - routes.Add(route); - } - } + var members = await cache.SortedSetRangeByScoreAsync("ROUTES", start, end); - return routes; - } + var entries = new List(); - public HashSet GetAllSources() - { - var sources = new HashSet(); - foreach (var key in _routeToLps.Keys) + foreach (var member in members) { - if (cache.TryGetValue(key, out var route)) + try { - sources.Add(route.Source); + var dto = JsonSerializer.Deserialize(member); + if (dto != null) + entries.Add(dto); } - } - return sources; - } - - public HashSet GetAllDestinations() - { - var destinations = new HashSet(); - foreach (var key in _routeToLps.Keys) - { - if (cache.TryGetValue(key, out var route)) + catch { - destinations.Add(route.Destionation); } } - return destinations; + return entries; } - public IEnumerable GetLpsByRoute(string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken) + public async Task> GetSolversByRouteAsync(string sourceNetwork, string sourceToken, string destinationNetwork, string destinationToken) { - var requestedRouteKey = GetRouteKey(sourceNetwork, sourceToken, destinationNetwork, destinationToken); - - if (_routeToLps.TryGetValue(requestedRouteKey, out var lps)) - { - return lps.Keys; - } - - return Enumerable.Empty(); + var members = await cache.SetMembersAsync(GetRouteKey("SOLVERS", sourceNetwork, sourceToken, destinationNetwork, destinationToken)); + return members.Select(m => m.ToString()); } - private static string GetRouteKey(string sourceNetwork, string sourceToken, string destNetwork, string destToken) + private static string GetRouteKey(string prefix, string sourceNetwork, string sourceToken, string destNetwork, string destToken) { - return $"{sourceNetwork}.{sourceToken}->{destNetwork}.{destToken}"; + return $"{prefix}:{sourceNetwork}.{sourceToken}->{destNetwork}.{destToken}"; } - private static string GetRouteKey(RouteDto r) + private static string GetRouteKey(string prefix, RouteDto r) { return GetRouteKey( + prefix, r.Source.Network.Name, r.Source.Token.Symbol, - r.Destionation.Network.Name, - r.Destionation.Token.Symbol + r.Destination.Network.Name, + r.Destination.Token.Symbol ); } } diff --git a/TrainStation/Services/RoutePollingService.cs b/TrainStation/Services/RoutePollingService.cs index fe06bee..2421f12 100644 --- a/TrainStation/Services/RoutePollingService.cs +++ b/TrainStation/Services/RoutePollingService.cs @@ -15,8 +15,8 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { - var name = lp.Name; - var baseAddress = lp.Url.ToString(); + var name = lp.Key; + var baseAddress = lp.Value.Url.ToString(); var trainSilverClient = new TrainSolverApiClient( baseAddress, @@ -29,7 +29,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) continue; } - routeCache.AddOrUpdateRoute(name, routesResponse.Data, TimeSpan.FromMinutes(10)); + await routeCache.AddOrUpdateRouteAsync(name, routesResponse.Data, TimeSpan.FromMinutes(5)); } catch (Exception ex) { diff --git a/TrainStation/Services/SolverCache.cs b/TrainStation/Services/SolverCache.cs index e01e0be..bf69caf 100644 --- a/TrainStation/Services/SolverCache.cs +++ b/TrainStation/Services/SolverCache.cs @@ -1,26 +1,12 @@ -using System.Text.Json; +using System.Collections.Concurrent; +using System.Text.Json; using Train.Station.API.Models; namespace Train.Station.API.Services; -public class SolverCache +public class SolverCache(IWebHostEnvironment env) + : JsonFileCache, Solver>( + env, "solvers.json", list => list.ToDictionary(x => x.Name)) { - private readonly List _solvers; - - public SolverCache(IWebHostEnvironment env) - { - var filePath = Path.Combine(env.ContentRootPath, "solvers.json"); - if (!File.Exists(filePath)) - { - throw new FileNotFoundException("Could not find lp.json", filePath); - } - - var json = File.ReadAllText(filePath); - _solvers = JsonSerializer.Deserialize>(json, new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true - }) ?? new List(); - } - - public IReadOnlyList GetAll() => _solvers; + public IReadOnlyDictionary GetAll() => Items; } \ No newline at end of file diff --git a/TrainStation/networks.json b/TrainStation/networks.json index ca6c277..423473d 100644 --- a/TrainStation/networks.json +++ b/TrainStation/networks.json @@ -5,9 +5,10 @@ "ChainId": "11155111", "TransactionExplorerTemplate": "https://sepolia.etherscan.io/tx/{0}", "AccountExplorerTemplate": "https://sepolia.etherscan.io/address/{0}", - "NativeSymbol": "ETH", - "Decimals": 18, - "RpcUrl": "https://ethereum-sepolia-rpc.publicnode.com" + "NativeTokenSymbol": "ETH", + "NativeTokenDecimals": 18, + "RpcUrl": "https://ethereum-sepolia-rpc.publicnode.com", + "Type": "EVM" }, { "Name": "ARBITRUM_SEPOLIA", @@ -15,9 +16,10 @@ "ChainId": "421614", "TransactionExplorerTemplate": "https://sepolia.arbiscan.io/tx/{0}", "AccountExplorerTemplate": "https://sepolia.arbiscan.io/address/{0}", - "NativeSymbol": "ETH", - "Decimals": 18, - "RpcUrl": "https://arbitrum-sepolia-rpc.publicnode.com" + "NativeTokenSymbol": "ETH", + "NativeTokenDecimals": 18, + "RpcUrl": "https://arbitrum-sepolia-rpc.publicnode.com", + "Type": "EVM" }, { "Name": "OPTIMISM_SEPOLIA", @@ -25,9 +27,10 @@ "ChainId": "11155420", "TransactionExplorerTemplate": "https://sepolia-optimism.etherscan.io/tx/{0}", "AccountExplorerTemplate": "https://sepolia-optimism.etherscan.io/address/{0}", - "NativeSymbol": "ETH", - "Decimals": 18, - "RpcUrl": "https://sepolia.optimism.io" + "NativeTokenSymbol": "ETH", + "NativeTokenDecimals": 18, + "RpcUrl": "https://sepolia.optimism.io", + "Type": "EVM" }, { "Name": "STARKNET_SEPOLIA", @@ -35,9 +38,10 @@ "ChainId": "0x534e5f5345504f4c4941", "TransactionExplorerTemplate": "https://sepolia.starkscan.co/tx/{0}", "AccountExplorerTemplate": "https://sepolia.starkscan.co/contract/{0}", - "NativeSymbol": "ETH", - "Decimals": 18, - "RpcUrl": "https://starknet-sepolia.public.blastapi.io" + "NativeTokenSymbol": "ETH", + "NativeTokenDecimals": 18, + "RpcUrl": "https://starknet-sepolia.public.blastapi.io", + "Type": "EVM" }, { "Name": "SOLANA_DEVNET", @@ -45,8 +49,20 @@ "ChainId": "devnet", "TransactionExplorerTemplate": "https://explorer.solana.com/tx/{0}?cluster=devnet", "AccountExplorerTemplate": "https://explorer.solana.com/address/{0}?cluster=devnet", - "NativeSymbol": "SOL", - "Decimals": 9, - "RpcUrl": "https://api.devnet.solana.com" + "NativeTokenSymbol": "SOL", + "NativeTokenDecimals": 9, + "RpcUrl": "https://api.devnet.solana.com", + "Type": "Solana" + }, + { + "Name": "FUEL_TESTNET", + "DisplayName": "Fuel Testnet", + "ChainId": "0", + "TransactionExplorerTemplate": "https://app-testnet.fuel.network/tx/{0}", + "AccountExplorerTemplate": "https://app-testnet.fuel.network/account/{0}/assets", + "NativeTokenSymbol": "ETH", + "NativeTokenDecimals": 9, + "RpcUrl": "https://testnet.fuel.network/v1/graphql", + "Type": "Fuel" } -] \ No newline at end of file +] diff --git a/TrainStation/solvers.json b/TrainStation/solvers.json index 9ffebca..028d9be 100644 --- a/TrainStation/solvers.json +++ b/TrainStation/solvers.json @@ -2,6 +2,6 @@ { "name": "EC69", "url": "https://train.dev.lb.layerswap.cloud", - "version" : "v1" + "version": "v1" } ] \ No newline at end of file