From fa8947933c828ca86f7b1074dbe07ba06d6ca300 Mon Sep 17 00:00:00 2001 From: Davit Mandzikyan Date: Wed, 13 Aug 2025 02:13:28 +0400 Subject: [PATCH 1/7] Fix feuls fee estimation. --- .../Activities/FuelBlockchainActivities.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts index 39bb5ab4..64b9d77a 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts @@ -40,8 +40,6 @@ export class FuelBlockchainActivities implements IFuelBlockchainActivities { // @inject("TreasuryClient") private treasuryClient: TreasuryClient ) { } - readonly MaxFeeMultiplier = 7; - readonly GasLimitMultiplier = 3; public async BuildTransaction(request: TransactionBuilderRequest): Promise { try { @@ -203,10 +201,11 @@ export class FuelBlockchainActivities implements IFuelBlockchainActivities { txRequest.addCoinInput(coin); } - const estimatedDependencies = await wallet.provider.estimateTxDependencies(txRequest); + const estimatedDependencies = await wallet.provider.getTransactionCost(txRequest); - txRequest.maxFee = bn(estimatedDependencies.dryRunStatus.totalFee).mul(this.MaxFeeMultiplier); - txRequest.gasLimit = bn(estimatedDependencies.dryRunStatus.totalGas).add(bn("100000").mul(this.GasLimitMultiplier)) + txRequest.maxFee = estimatedDependencies.maxFee; + + txRequest.gasLimit = estimatedDependencies.gasUsed; await this.ensureSufficientBalance( { From 37f035d3e1c9d4ed42652858f593c6fa5c4b977f Mon Sep 17 00:00:00 2001 From: Mandzikyan <87118120+Mandzikyan@users.noreply.github.com> Date: Wed, 13 Aug 2025 15:09:18 +0400 Subject: [PATCH 2/7] Create fuel transfer prepare. (#118) * Create fuel transfer prepare. * Fix estimate. --------- Co-authored-by: Davit Mandzikyan --- .../Activities/FuelBlockchainActivities.ts | 46 ++++++++++--------- .../Helper/FuelTransactionBuilder.ts | 34 +++++++++++++- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts index 64b9d77a..53f38a4c 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts @@ -5,7 +5,7 @@ import { GetTransactionRequest } from "../../Blockchain.Abstraction/Models/Recei import { TransactionResponse } from "../../Blockchain.Abstraction/Models/ReceiptModels/TransactionResponse"; import { TransactionBuilderRequest } from "../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransactionBuilderRequest"; import { PrepareTransactionResponse } from "../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransferBuilderResponse"; -import { BigNumberCoder, Provider, Wallet, Signer, sha256, DateTime, bn, hashMessage, B256Coder, concat, Address, isTransactionTypeScript, transactionRequestify, ScriptTransactionRequest } from "fuels"; +import { BigNumberCoder, Provider, Wallet, Signer, sha256, DateTime, bn, hashMessage, B256Coder, concat, Address, isTransactionTypeScript, transactionRequestify, ScriptTransactionRequest} from "fuels"; import { TransactionStatus } from '../../Blockchain.Abstraction/Models/TransacitonModels/TransactionStatus'; import { TransactionType } from "../../Blockchain.Abstraction/Models/TransacitonModels/TransactionType"; import { IFuelBlockchainActivities } from "./IFuelBlockchainActivities"; @@ -14,7 +14,7 @@ import { BalanceResponse } from "../../Blockchain.Abstraction/Models/BalanceRequ import { BaseRequest } from "../../Blockchain.Abstraction/Models/BaseRequest"; import { AddLockSignatureRequest } from "../../Blockchain.Abstraction/Models/TransactionBuilderModels/AddLockSignatureRequest"; import TrackBlockEventsAsync from "./Helper/FuelEventTracker"; -import { createAddLockSigCallData, createRefundCallData, createLockCallData, createRedeemCallData, createCommitCallData } from "./Helper/FuelTransactionBuilder"; +import { createAddLockSigCallData, createRefundCallData, createLockCallData, createRedeemCallData, createCommitCallData, createTransferCallData } from "./Helper/FuelTransactionBuilder"; import { FuelPublishTransactionRequest } from "../Models/FuelPublishTransactionRequest"; import { mapFuelStatusToInternal } from "./Helper/FuelTransactionStatusMapper"; import { FuelComposeTransactionRequest } from "../Models/FuelComposeTransactionRequest"; @@ -41,27 +41,29 @@ export class FuelBlockchainActivities implements IFuelBlockchainActivities { ) { } - public async BuildTransaction(request: TransactionBuilderRequest): Promise { - try { - switch (request.type) { - case TransactionType.HTLCLock: - return createLockCallData(request.network, request.prepareArgs); - case TransactionType.HTLCRedeem: - return createRedeemCallData(request.network, request.prepareArgs); - case TransactionType.HTLCRefund: - return createRefundCallData(request.network, request.prepareArgs); - case TransactionType.HTLCAddLockSig: - return createAddLockSigCallData(request.network, request.prepareArgs); - case TransactionType.HTLCCommit: - return createCommitCallData(request.network, request.prepareArgs); - default: - throw new Error(`Unknown function name ${request.type}`); - } - } - catch (error) { - throw error; + public async BuildTransaction(request: TransactionBuilderRequest): Promise { + try { + switch (request.type) { + case TransactionType.HTLCLock: + return createLockCallData(request.network, request.prepareArgs); + case TransactionType.HTLCRedeem: + return createRedeemCallData(request.network, request.prepareArgs); + case TransactionType.HTLCRefund: + return createRefundCallData(request.network, request.prepareArgs); + case TransactionType.HTLCAddLockSig: + return createAddLockSigCallData(request.network, request.prepareArgs); + case TransactionType.HTLCCommit: + return createCommitCallData(request.network, request.prepareArgs); + case TransactionType.Transfer: + return createTransferCallData(request.network, request.prepareArgs); + default: + throw new Error(`Unknown function name ${request.type}`); + } + } + catch (error) { + throw error; + } } - } public async GetBalance(request: BalanceRequest): Promise { diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelTransactionBuilder.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelTransactionBuilder.ts index 79dc1afb..7f290978 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelTransactionBuilder.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelTransactionBuilder.ts @@ -5,9 +5,10 @@ import { HTLCRedeemTransactionPrepareRequest } from "../../../Blockchain.Abstrac import { HTLCRefundTransactionPrepareRequest } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/HTLCRefundTransactionPrepareRequest"; import { HTLCCommitTransactionPrepareRequest } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/HTLCCommitTransactionPrepareRequest"; import { PrepareTransactionResponse } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransferBuilderResponse"; -import { Address, AssetId, B256Address, bn, Contract, DateTime, formatUnits, Provider } from "fuels"; +import { Address, AssetId, B256Address, bn, Contract, DateTime, formatUnits, Provider, ScriptTransactionRequest, Wallet } from "fuels"; import abi from '../ABIs/train.json'; import { DetailedNetworkDto } from "../../../Blockchain.Abstraction/Models/DetailedNetworkDto"; +import { TransferPrepareRequest } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransferPrepareRequest"; export async function createRefundCallData(network: DetailedNetworkDto, args: string): Promise { @@ -87,7 +88,7 @@ export async function createCommitCallData(network: DetailedNetworkDto, args: st maxFee: bn(1000000), }); - const txRequest = await callConfig.getTransactionRequest(); + const txRequest = await callConfig.getTransactionRequest(); return { data: JSON.stringify(txRequest), @@ -230,6 +231,35 @@ export async function createAddLockSigCallData(network: DetailedNetworkDto, args }; } +export async function createTransferCallData(network: DetailedNetworkDto, args: string): Promise { + + const transferRequest = decodeJson(args); + const token = network.tokens.find(t => t.symbol === transferRequest.asset); + + if (!token) { + throw new Error(`Token not found for network ${network.name} and asset ${transferRequest.asset}`) + }; + + const provider = new Provider(network.nodes[0].url); + const wallet = Wallet.fromAddress(transferRequest.fromAddress, provider); + + const transactionRequest: ScriptTransactionRequest = await wallet.createTransfer( + transferRequest.toAddress, + transferRequest.amount, + token.contract, + ); + + return { + data: JSON.stringify(transactionRequest), + amount: transferRequest.amount.toString(), + asset: token.symbol, + callDataAsset: token.symbol, + callDataAmount: transferRequest.amount.toString(), + toAddress: transferRequest.toAddress, + }; + +} + function PadStringsTo64(input: string[]): string[] { return input.map(str => str.padEnd(64, ' ')); } From d921ef92da5150129989a0d887557463681de661 Mon Sep 17 00:00:00 2001 From: Ruben Date: Wed, 13 Aug 2025 15:26:28 +0400 Subject: [PATCH 3/7] Add get rebalances endpoint --- .../AdminAPI/Endpoints/RebalanceEndpoints.cs | 51 ++++++++++++++++--- csharp/src/AdminAPI/Models/RebalanceEntry.cs | 14 +++++ .../src/AdminAPI/Models/RebalanceSummary.cs | 16 ++++++ 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 csharp/src/AdminAPI/Models/RebalanceEntry.cs create mode 100644 csharp/src/AdminAPI/Models/RebalanceSummary.cs diff --git a/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs b/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs index 617ac22a..24795409 100644 --- a/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs +++ b/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs @@ -19,7 +19,7 @@ public static class RebalanceEndpoints public static RouteGroupBuilder MapRebalanceEndpoints(this RouteGroupBuilder group) { group.MapGet("/rebalance", GetAllAsync) - .Produces(StatusCodes.Status200OK); + .Produces>(StatusCodes.Status200OK); group.MapPost("/rebalance", RebalanceAsync) .Produces(StatusCodes.Status200OK); @@ -30,17 +30,47 @@ public static RouteGroupBuilder MapRebalanceEndpoints(this RouteGroupBuilder gro private static async Task GetAllAsync( ITemporalClient temporalClient) { - var query = $"`WorkflowId` STARTS_WITH \"Rebalance\" AND `ExecutionStatus`=\"Running\""; - var results = new List(); + var query = $"`WorkflowId` STARTS_WITH \"Rebalance\""; + var results = new List(); - await foreach (var wf in temporalClient.ListWorkflowsAsync(query)) + await foreach (var wf in temporalClient.ListWorkflowsAsync(query, new WorkflowListOptions + { + Limit = 10, + })) { var whHandle = temporalClient.GetWorkflowHandle(wf.Id); var describedWorkflow = await whHandle.DescribeAsync(); if (describedWorkflow.Memo.TryGetValue("Summary", out var summary) && summary != null) { - results.Add(summary.ToString()!); + var decoded = temporalClient.Options.DataConverter.ToValueAsync(summary.Payload); + + try + { + var rebalanceEntry = new RebalanceEntry + { + Id = wf.Id, + Status = wf.Status.ToString(), + Summary = decoded.Result.FromJson(), + }; + + if (wf.Status == WorkflowExecutionStatus.Completed) + { + var wfResult = await whHandle.GetResultAsync(); + + rebalanceEntry.Transaction = new TransactionDto + { + Hash = wfResult.TransactionHash, + Network = wfResult.NetworkName, + Type = TransactionType.Transfer, + }; + } + + results.Add(rebalanceEntry); + } + catch (Exception) + { + } } } @@ -83,6 +113,15 @@ private static async Task RebalanceAsync( return Results.NotFound($"Trusted wallet {request.ToAddress} not found on network {request.NetworkName}"); } + var summary = new RebalanceSummary + { + Amount = request.Amount.ToString(), + Network = network.ToExtendedDto(), + Token = token.ToDto(), + From = wallet.ToDto(), + To = trustedWallet.ToDto(), + }; + var workflowId = await temporalClient.StartWorkflowAsync( TemporalHelper.ResolveProcessor(network.Type), [new TransactionRequest() { @@ -105,7 +144,7 @@ private static async Task RebalanceAsync( IdReusePolicy = WorkflowIdReusePolicy.TerminateIfRunning, Memo = new Dictionary { - { "Summary", $"Rebalancing { TokenUnitHelper.FromBaseUnits(request.Amount, token.Decimals) } {token.Asset} in {network.DisplayName} from {wallet.Address} to {trustedWallet.Address}" }, + { "Summary", summary.ToJson()}, } }); diff --git a/csharp/src/AdminAPI/Models/RebalanceEntry.cs b/csharp/src/AdminAPI/Models/RebalanceEntry.cs new file mode 100644 index 00000000..185ecf3f --- /dev/null +++ b/csharp/src/AdminAPI/Models/RebalanceEntry.cs @@ -0,0 +1,14 @@ +using Train.Solver.Infrastructure.Abstractions.Models; + +namespace Train.Solver.AdminAPI.Models; + +public class RebalanceEntry +{ + public required RebalanceSummary Summary { get; set; } + + public required string Id { get; set; } + + public required string Status { get; set; } + + public TransactionDto? Transaction { get; set; } +} diff --git a/csharp/src/AdminAPI/Models/RebalanceSummary.cs b/csharp/src/AdminAPI/Models/RebalanceSummary.cs new file mode 100644 index 00000000..7737167f --- /dev/null +++ b/csharp/src/AdminAPI/Models/RebalanceSummary.cs @@ -0,0 +1,16 @@ +using Train.Solver.Infrastructure.Abstractions.Models; + +namespace Train.Solver.AdminAPI.Models; + +public class RebalanceSummary +{ + public required ExtendedNetworkDto Network { get; set; } + + public required TokenDto Token { get; set; } + + public required string Amount { get; set; } + + public required WalletDto From { get; set; } + + public required TrustedWalletDto To { get; set; } +} From 0243e96d5a7e1c7c51a6eeda1b8e533c6c269293 Mon Sep 17 00:00:00 2001 From: Ruben Date: Wed, 13 Aug 2025 16:20:47 +0400 Subject: [PATCH 4/7] Add get swaps --- csharp/src/AdminAPI/Endpoints/SwapEndpoints.cs | 12 ++++++++++++ .../Repositories/ISwapRepository.cs | 2 +- csharp/src/Data.Npgsql/EFSwapRepository.cs | 5 +---- .../Infrastructure.Abstractions/Models/SwapDto.cs | 4 ++-- .../Infrastructure/Extensions/MapperExtensions.cs | 4 ++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/csharp/src/AdminAPI/Endpoints/SwapEndpoints.cs b/csharp/src/AdminAPI/Endpoints/SwapEndpoints.cs index cab5b84c..71d3ac9a 100644 --- a/csharp/src/AdminAPI/Endpoints/SwapEndpoints.cs +++ b/csharp/src/AdminAPI/Endpoints/SwapEndpoints.cs @@ -11,12 +11,24 @@ public static class SwapEndpoints { public static RouteGroupBuilder MapSwapEndpoints(this RouteGroupBuilder group) { + group.MapGet("/swaps", GetAllAsync) + .Produces>(); + group.MapGet("/swaps/{commitId}", GetAsync) .Produces(); return group; } + private static async Task GetAllAsync( + ISwapRepository repository, + uint page = 1) + { + var swaps = await repository.GetAllAsync(page); + + return Results.Ok(swaps.Select(x => x.ToDto())); + } + private static async Task GetAsync( string commitId, ISwapRepository repository) diff --git a/csharp/src/Data.Abstractions/Repositories/ISwapRepository.cs b/csharp/src/Data.Abstractions/Repositories/ISwapRepository.cs index 65b65218..65129045 100644 --- a/csharp/src/Data.Abstractions/Repositories/ISwapRepository.cs +++ b/csharp/src/Data.Abstractions/Repositories/ISwapRepository.cs @@ -7,7 +7,7 @@ public interface ISwapRepository { Task GetAsync(string commitId); - Task> GetAllAsync(uint page = 1, uint size = 20, string[]? addresses = null); + Task> GetAllAsync(uint page = 1, uint size = 20); Task> GetNonRefundedSwapIdsAsync(); diff --git a/csharp/src/Data.Npgsql/EFSwapRepository.cs b/csharp/src/Data.Npgsql/EFSwapRepository.cs index 4726857f..e42b56e4 100644 --- a/csharp/src/Data.Npgsql/EFSwapRepository.cs +++ b/csharp/src/Data.Npgsql/EFSwapRepository.cs @@ -53,12 +53,9 @@ public async Task CreateAsync( return swap; } - public async Task> GetAllAsync(uint page = 1, uint size = 20, string[]? addresses = null) + public async Task> GetAllAsync(uint page = 1, uint size = 15) { return await GetBaseQuery() - .Where(x => addresses == null - || addresses.Contains(x.SourceAddress.ToLower()) - || addresses.Contains(x.DestinationAddress.ToLower())) .OrderByDescending(x => x.CreatedDate) .Skip((int)(page * size)) .Take((int)size) diff --git a/csharp/src/Infrastructure.Abstractions/Models/SwapDto.cs b/csharp/src/Infrastructure.Abstractions/Models/SwapDto.cs index c7f49f02..bb5cba5c 100644 --- a/csharp/src/Infrastructure.Abstractions/Models/SwapDto.cs +++ b/csharp/src/Infrastructure.Abstractions/Models/SwapDto.cs @@ -8,7 +8,7 @@ public class SwapDto public string Hashlock { get; set; } = null!; - public TokenNetworkDto Source { get; set; } = null!; + public ExtendedTokenNetworkDto Source { get; set; } = null!; public BigInteger SourceAmount { get; set; } @@ -16,7 +16,7 @@ public class SwapDto public string SourceContractAddress { get; set; } = null!; - public TokenNetworkDto Destination { get; set; } = null!; + public ExtendedTokenNetworkDto Destination { get; set; } = null!; public BigInteger DestinationAmount { get; set; } diff --git a/csharp/src/Infrastructure/Extensions/MapperExtensions.cs b/csharp/src/Infrastructure/Extensions/MapperExtensions.cs index e21926ca..46252e62 100644 --- a/csharp/src/Infrastructure/Extensions/MapperExtensions.cs +++ b/csharp/src/Infrastructure/Extensions/MapperExtensions.cs @@ -12,13 +12,13 @@ public static SwapDto ToDto(this Swap swap) { CommitId = swap.CommitId, Hashlock = swap.Hashlock, - Source = swap.Route.SourceToken.ToWithNetworkDto(), + Source = swap.Route.SourceToken.ToWithExtendedNetworkDto(), SourceAmount = BigInteger.Parse(swap.SourceAmount), SourceAddress = swap.SourceAddress, SourceContractAddress = swap.Route.SourceTokenId == swap.Route.SourceToken.Network.NativeTokenId ? swap.Route.SourceToken.Network.HTLCNativeContractAddress : swap.Route.SourceToken.Network.HTLCTokenContractAddress, - Destination = swap.Route.DestinationToken.ToWithNetworkDto(), + Destination = swap.Route.DestinationToken.ToWithExtendedNetworkDto(), DestinationAddress = swap.DestinationAddress, DestinationContractAddress = swap.Route.DestinationTokenId == swap.Route.DestinationToken.Network.NativeTokenId ? swap.Route.DestinationToken.Network.HTLCNativeContractAddress : From 0c2dbbeb93ebf1ce462de6e5d0fc3bc598b49229 Mon Sep 17 00:00:00 2001 From: Mandzikyan <87118120+Mandzikyan@users.noreply.github.com> Date: Wed, 13 Aug 2025 16:39:38 +0400 Subject: [PATCH 5/7] Dev fuel transfer prepare (#119) * Create fuel transfer prepare. * Fix estimate. * Fix. --------- Co-authored-by: Davit Mandzikyan --- .../Activities/FuelBlockchainActivities.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts index 53f38a4c..db0fcda3 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts @@ -197,16 +197,20 @@ export class FuelBlockchainActivities implements IFuelBlockchainActivities { const txRequest = ScriptTransactionRequest.from(transactionRequestify(requestData)); - const balance = await wallet.getCoins(await provider.getBaseAssetId()); + const coinInputs = txRequest.getCoinInputs(); - for (const coin of balance.coins) { - txRequest.addCoinInput(coin); + if (!coinInputs.length) { + const balance = await wallet.getCoins(await provider.getBaseAssetId()); + + for (const coin of balance.coins) { + txRequest.addCoinInput(coin); + } } const estimatedDependencies = await wallet.provider.getTransactionCost(txRequest); txRequest.maxFee = estimatedDependencies.maxFee; - + txRequest.gasLimit = estimatedDependencies.gasUsed; await this.ensureSufficientBalance( From 2daeea18daffb3f4547fa99417b8e27d08028786 Mon Sep 17 00:00:00 2001 From: Ruben Date: Wed, 13 Aug 2025 17:00:24 +0400 Subject: [PATCH 6/7] Make to address be wallet as well --- .../AdminAPI/Endpoints/RebalanceEndpoints.cs | 20 +++++++++++++++---- .../src/AdminAPI/Models/RebalanceSummary.cs | 4 ++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs b/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs index 24795409..f000432c 100644 --- a/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs +++ b/csharp/src/AdminAPI/Endpoints/RebalanceEndpoints.cs @@ -106,11 +106,23 @@ private static async Task RebalanceAsync( return Results.NotFound($"Wallet {request.FromAddress} not found on network {request.NetworkName}"); } + string toAddress; var trustedWallet = await trustedWalletRepository.GetAsync(network.Type, request.ToAddress); if (trustedWallet is null) { - return Results.NotFound($"Trusted wallet {request.ToAddress} not found on network {request.NetworkName}"); + var toWallet = await walletRepository.GetAsync(network.Type, request.ToAddress); + + if (toWallet == null) + { + return Results.BadRequest($"To address {request.ToAddress} is not a trusted wallet, but a regular wallet."); + } + + toAddress = toWallet.Address; + } + else + { + toAddress = trustedWallet.Address; } var summary = new RebalanceSummary @@ -118,8 +130,8 @@ private static async Task RebalanceAsync( Amount = request.Amount.ToString(), Network = network.ToExtendedDto(), Token = token.ToDto(), - From = wallet.ToDto(), - To = trustedWallet.ToDto(), + From = wallet.Address, + To = toAddress, }; var workflowId = await temporalClient.StartWorkflowAsync( @@ -130,7 +142,7 @@ private static async Task RebalanceAsync( Amount = request.Amount, Asset = token.Asset, FromAddress = wallet.Address, - ToAddress = trustedWallet.Address, + ToAddress = toAddress, }.ToJson(), Type = TransactionType.Transfer, Network = network.ToDetailedDto(), diff --git a/csharp/src/AdminAPI/Models/RebalanceSummary.cs b/csharp/src/AdminAPI/Models/RebalanceSummary.cs index 7737167f..da1c8876 100644 --- a/csharp/src/AdminAPI/Models/RebalanceSummary.cs +++ b/csharp/src/AdminAPI/Models/RebalanceSummary.cs @@ -10,7 +10,7 @@ public class RebalanceSummary public required string Amount { get; set; } - public required WalletDto From { get; set; } + public required string From { get; set; } - public required TrustedWalletDto To { get; set; } + public required string To { get; set; } } From 46a8e42837d3bbbbf1dea575dd332091f0943e0c Mon Sep 17 00:00:00 2001 From: Ruben Date: Wed, 13 Aug 2025 17:12:46 +0400 Subject: [PATCH 7/7] Add token price create endpoint --- .../AdminAPI/Endpoints/TokenPriceEndpoints.cs | 17 ++++++++++++++++- .../AdminAPI/Models/CreateTokenPriceRequest.cs | 8 ++++++++ .../Repositories/ITokenPriceRepository.cs | 2 ++ .../src/Data.Npgsql/EFTokenPriceRepository.cs | 14 ++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 csharp/src/AdminAPI/Models/CreateTokenPriceRequest.cs diff --git a/csharp/src/AdminAPI/Endpoints/TokenPriceEndpoints.cs b/csharp/src/AdminAPI/Endpoints/TokenPriceEndpoints.cs index 25ab9c86..dde4adf0 100644 --- a/csharp/src/AdminAPI/Endpoints/TokenPriceEndpoints.cs +++ b/csharp/src/AdminAPI/Endpoints/TokenPriceEndpoints.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Train.Solver.AdminAPI.Models; using Train.Solver.Common.Enums; using Train.Solver.Data.Abstractions.Entities; using Train.Solver.Data.Abstractions.Repositories; @@ -14,12 +15,26 @@ public static RouteGroupBuilder MapTokenPriceEndpoints(this RouteGroupBuilder gr group.MapGet("/token-prices", GetAllTokenPricesAsync) .Produces>(); + group.MapPost("/token-prices", CreateTokenPriceAsync) + .Produces(200); + return group; } private static async Task GetAllTokenPricesAsync(ITokenPriceRepository repository) { var tokenPrices = await repository.GetAllAsync(); - return Results.Ok(tokenPrices.Select(x=>x.ToDto())); + return Results.Ok(tokenPrices.Select(x => x.ToDto())); + } + + private static async Task CreateTokenPriceAsync( + ITokenPriceRepository repository, + CreateTokenPriceRequest request) + { + var tokenPrice = await repository.CreateAsync(request.Symbol, request.ExternalId); + + return tokenPrice is null + ? Results.BadRequest("Failed to create token price") + : Results.Ok(); } } \ No newline at end of file diff --git a/csharp/src/AdminAPI/Models/CreateTokenPriceRequest.cs b/csharp/src/AdminAPI/Models/CreateTokenPriceRequest.cs new file mode 100644 index 00000000..10f02b00 --- /dev/null +++ b/csharp/src/AdminAPI/Models/CreateTokenPriceRequest.cs @@ -0,0 +1,8 @@ +namespace Train.Solver.AdminAPI.Models; + +public class CreateTokenPriceRequest +{ + public string Symbol { get; set; } = null!; + + public string ExternalId { get; set; } = null!; +} diff --git a/csharp/src/Data.Abstractions/Repositories/ITokenPriceRepository.cs b/csharp/src/Data.Abstractions/Repositories/ITokenPriceRepository.cs index e7f2dffd..8abcb878 100644 --- a/csharp/src/Data.Abstractions/Repositories/ITokenPriceRepository.cs +++ b/csharp/src/Data.Abstractions/Repositories/ITokenPriceRepository.cs @@ -8,5 +8,7 @@ public interface ITokenPriceRepository Task GetAsync(string symbol); + Task CreateAsync(string symbol, string externalId); + Task UpdateAsync(Dictionary prices); } diff --git a/csharp/src/Data.Npgsql/EFTokenPriceRepository.cs b/csharp/src/Data.Npgsql/EFTokenPriceRepository.cs index 1a7e6db8..03fdef0c 100644 --- a/csharp/src/Data.Npgsql/EFTokenPriceRepository.cs +++ b/csharp/src/Data.Npgsql/EFTokenPriceRepository.cs @@ -6,6 +6,20 @@ namespace Train.Solver.Data.Npgsql; public class EFTokenPriceRepository(SolverDbContext dbContext) : ITokenPriceRepository { + public async Task CreateAsync(string symbol, string externalId) + { + var tokenPrice = new TokenPrice + { + Symbol = symbol, + ExternalId = externalId, + }; + + dbContext.TokenPrices.Add(tokenPrice); + await dbContext.SaveChangesAsync(); + + return tokenPrice; + } + public async Task> GetAllAsync() { return await dbContext.TokenPrices.ToListAsync();