From 549c4ae746a592df1b3c8270382f49809cfe9628 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Sat, 10 May 2025 14:41:17 +0700 Subject: [PATCH] Add initAddress api --- .../Controllers/TradingController.cs | 30 ++++++ .../Repositories/IEvmManager.cs | 3 +- .../Services/ITradingService.cs | 2 + .../Trading/TradingService.cs | 28 +++++- .../Evm}/PrivyInitAddressResponse.cs | 0 .../EvmManagerTests.cs | 2 +- .../EvmManager.cs | 10 +- .../src/plugins/custom/gmx.ts | 3 + .../src/generated/ManagingApi.ts | 47 ++++++++++ .../settingsPage/account/accountTable.tsx | 91 +++++++++++-------- 10 files changed, 170 insertions(+), 46 deletions(-) rename src/{Managing.Infrastructure.Web3/Models/Privy => Managing.Domain/Evm}/PrivyInitAddressResponse.cs (100%) diff --git a/src/Managing.Api/Controllers/TradingController.cs b/src/Managing.Api/Controllers/TradingController.cs index 7d07806..891b9c1 100644 --- a/src/Managing.Api/Controllers/TradingController.cs +++ b/src/Managing.Api/Controllers/TradingController.cs @@ -3,6 +3,7 @@ using Managing.Application.Abstractions.Services; using Managing.Application.Trading.Commands; using Managing.Domain.MoneyManagements; using Managing.Domain.Trades; +using Managing.Infrastructure.Evm.Models.Privy; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -156,4 +157,33 @@ public class TradingController : BaseController var result = await _openTradeCommandHandler.Handle(command); return Ok(result); } + + /// + /// Initializes a Privy wallet address for the user. + /// + /// The public address of the Privy wallet to initialize. + /// The initialization response containing success status and transaction hashes. + [HttpPost("InitPrivyWallet")] + public async Task> InitPrivyWallet([FromBody] string publicAddress) + { + if (string.IsNullOrEmpty(publicAddress)) + { + return BadRequest("Public address cannot be null or empty."); + } + + try + { + var result = await _tradingService.InitPrivyWallet(publicAddress); + return Ok(result); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error initializing Privy wallet address: {Address}", publicAddress); + return StatusCode(500, new PrivyInitAddressResponse + { + Success = false, + Error = "An error occurred while initializing the Privy wallet address." + }); + } + } } \ No newline at end of file diff --git a/src/Managing.Application.Abstractions/Repositories/IEvmManager.cs b/src/Managing.Application.Abstractions/Repositories/IEvmManager.cs index e2bc235..2c95f36 100644 --- a/src/Managing.Application.Abstractions/Repositories/IEvmManager.cs +++ b/src/Managing.Application.Abstractions/Repositories/IEvmManager.cs @@ -3,6 +3,7 @@ using Managing.Domain.Candles; using Managing.Domain.Evm; using Managing.Domain.Statistics; using Managing.Domain.Trades; +using Managing.Infrastructure.Evm.Models.Privy; using static Managing.Common.Enums; namespace Managing.Application.Abstractions.Repositories; @@ -25,7 +26,7 @@ public interface IEvmManager decimal GetVolume(SubgraphProvider subgraphProvider, Ticker ticker); Task> GetAvailableTicker(); Task GetCandle(Ticker ticker); - Task InitAddress(string publicAddress); + Task InitAddress(string publicAddress); Task Send(Chain chain, Ticker ticker, decimal amount, string publicAddress, string privateKey, string receiverAddress); diff --git a/src/Managing.Application.Abstractions/Services/ITradingService.cs b/src/Managing.Application.Abstractions/Services/ITradingService.cs index 302027f..86e4b4b 100644 --- a/src/Managing.Application.Abstractions/Services/ITradingService.cs +++ b/src/Managing.Application.Abstractions/Services/ITradingService.cs @@ -3,6 +3,7 @@ using Managing.Domain.Scenarios; using Managing.Domain.Statistics; using Managing.Domain.Strategies; using Managing.Domain.Trades; +using Managing.Infrastructure.Evm.Models.Privy; using static Managing.Common.Enums; namespace Managing.Application.Abstractions.Services; @@ -35,4 +36,5 @@ public interface ITradingService void UpdateScenario(Scenario scenario); void UpdateStrategy(Strategy strategy); Task> GetBrokerPositions(Account account); + Task InitPrivyWallet(string publicAddress); } \ No newline at end of file diff --git a/src/Managing.Application/Trading/TradingService.cs b/src/Managing.Application/Trading/TradingService.cs index abe014d..4e8ebb1 100644 --- a/src/Managing.Application/Trading/TradingService.cs +++ b/src/Managing.Application/Trading/TradingService.cs @@ -1,5 +1,4 @@ -using Managing.Application.Abstractions; -using Managing.Application.Abstractions.Repositories; +using Managing.Application.Abstractions.Repositories; using Managing.Application.Abstractions.Services; using Managing.Domain.Accounts; using Managing.Domain.Scenarios; @@ -7,6 +6,7 @@ using Managing.Domain.Shared.Helpers; using Managing.Domain.Statistics; using Managing.Domain.Strategies; using Managing.Domain.Trades; +using Managing.Infrastructure.Evm.Models.Privy; using Microsoft.Extensions.Logging; using static Managing.Common.Enums; @@ -20,6 +20,7 @@ public class TradingService : ITradingService private readonly ICacheService _cacheService; private readonly IMessengerService _messengerService; private readonly IStatisticRepository _statisticRepository; + private readonly IEvmManager _evmManager; private readonly ILogger _logger; public TradingService( @@ -29,7 +30,8 @@ public class TradingService : ITradingService IAccountService accountService, ICacheService cacheService, IMessengerService messengerService, - IStatisticRepository statisticRepository) + IStatisticRepository statisticRepository, + IEvmManager evmManager) { _tradingRepository = tradingRepository; _exchangeService = exchangeService; @@ -38,6 +40,7 @@ public class TradingService : ITradingService _cacheService = cacheService; _messengerService = messengerService; _statisticRepository = statisticRepository; + _evmManager = evmManager; } public void DeleteScenario(string name) @@ -374,4 +377,23 @@ public class TradingService : ITradingService public List Trades { get; set; } public List PositionIdentifiers { get; set; } } + + public async Task InitPrivyWallet(string publicAddress) + { + try + { + if (string.IsNullOrEmpty(publicAddress)) + { + _logger.LogWarning("Attempted to initialize Privy wallet with null or empty public address"); + return new PrivyInitAddressResponse { Success = false, Error = "Public address cannot be null or empty" }; + } + + return await _evmManager.InitAddress(publicAddress); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error initializing Privy wallet for address {PublicAddress}", publicAddress); + return new PrivyInitAddressResponse { Success = false, Error = ex.Message }; + } + } } \ No newline at end of file diff --git a/src/Managing.Infrastructure.Web3/Models/Privy/PrivyInitAddressResponse.cs b/src/Managing.Domain/Evm/PrivyInitAddressResponse.cs similarity index 100% rename from src/Managing.Infrastructure.Web3/Models/Privy/PrivyInitAddressResponse.cs rename to src/Managing.Domain/Evm/PrivyInitAddressResponse.cs diff --git a/src/Managing.Infrastructure.Tests/EvmManagerTests.cs b/src/Managing.Infrastructure.Tests/EvmManagerTests.cs index af8b807..faa7633 100644 --- a/src/Managing.Infrastructure.Tests/EvmManagerTests.cs +++ b/src/Managing.Infrastructure.Tests/EvmManagerTests.cs @@ -210,7 +210,7 @@ public class EvmManagerTests { var accountInitilized = await _manager.InitAddress(PublicAddress); - Assert.True(accountInitilized); + Assert.NotNull(accountInitilized); } [Ignore] diff --git a/src/Managing.Infrastructure.Web3/EvmManager.cs b/src/Managing.Infrastructure.Web3/EvmManager.cs index f747211..eb4a21a 100644 --- a/src/Managing.Infrastructure.Web3/EvmManager.cs +++ b/src/Managing.Infrastructure.Web3/EvmManager.cs @@ -444,7 +444,7 @@ public class EvmManager : IEvmManager return cachedCandle; } - public async Task InitAddress(string publicAddress) + public async Task InitAddress(string publicAddress) { try { @@ -452,13 +452,17 @@ public class EvmManager : IEvmManager "/init-address", new { address = publicAddress }); - return response.Success; + return response; } catch (Exception ex) { // Log the error Console.Error.WriteLine($"Error initializing address: {ex.Message}"); - return false; + return new PrivyInitAddressResponse + { + Success = false, + Error = ex.Message + }; } } diff --git a/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts b/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts index a13e5f2..1f9e04c 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts @@ -150,6 +150,9 @@ export async function getClientForAddress( "0xdf034cd3df9a80eABFA0556232a91E03Ca67D5Cb": { isListed: false, }, + "0x9e79146b3A022Af44E0708c6794F03Ef798381A5": { + isListed: false, + }, } }; diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts index 086f8cd..7e24bc2 100644 --- a/src/Managing.WebApp/src/generated/ManagingApi.ts +++ b/src/Managing.WebApp/src/generated/ManagingApi.ts @@ -2159,6 +2159,45 @@ export class TradingClient extends AuthorizedApiBase { } return Promise.resolve(null as any); } + + trading_InitPrivyWallet(publicAddress: string): Promise { + let url_ = this.baseUrl + "/Trading/InitPrivyWallet"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(publicAddress); + + let options_: RequestInit = { + body: content_, + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json" + } + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.http.fetch(url_, transformedOptions_); + }).then((_response: Response) => { + return this.processTrading_InitPrivyWallet(_response); + }); + } + + protected processTrading_InitPrivyWallet(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as PrivyInitAddressResponse; + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } } export class UserClient extends AuthorizedApiBase { @@ -3072,6 +3111,14 @@ export enum RiskLevel { Adaptive = "Adaptive", } +export interface PrivyInitAddressResponse { + success?: boolean; + usdcHash?: string | null; + orderVaultHash?: string | null; + exchangeRouterHash?: string | null; + error?: string | null; +} + export interface LoginRequest { name: string; address: string; diff --git a/src/Managing.WebApp/src/pages/settingsPage/account/accountTable.tsx b/src/Managing.WebApp/src/pages/settingsPage/account/accountTable.tsx index 2f2fc90..e1640d8 100644 --- a/src/Managing.WebApp/src/pages/settingsPage/account/accountTable.tsx +++ b/src/Managing.WebApp/src/pages/settingsPage/account/accountTable.tsx @@ -1,21 +1,12 @@ -import { - ChevronDownIcon, - ChevronRightIcon, - ClipboardCopyIcon, - TrashIcon, -} from '@heroicons/react/solid' -import React, { useEffect, useState, useMemo } from 'react' -import { useNavigate } from 'react-router-dom' -import { FiPlus, FiTrash2, FiKey, FiTrendingUp } from 'react-icons/fi' +import {ChevronDownIcon, ChevronRightIcon,} from '@heroicons/react/solid' +import React, {useEffect, useMemo, useState} from 'react' +import {useNavigate} from 'react-router-dom' +import {FiKey, FiPlay, FiTrash2, FiTrendingUp} from 'react-icons/fi' import useApiUrlStore from '../../../app/store/apiStore' -import { - SelectColumnFilter, - Table, - Toast, -} from '../../../components/mollecules' -import type { Account } from '../../../generated/ManagingApi' -import { AccountClient, AccountType } from '../../../generated/ManagingApi' +import {SelectColumnFilter, Table, Toast,} from '../../../components/mollecules' +import type {Account} from '../../../generated/ManagingApi' +import {AccountClient, AccountType, TradingClient} from '../../../generated/ManagingApi' import AccountRowDetails from './accountRowDetails' import PrivyDelegationModal from './PrivyDelegationModal' @@ -48,6 +39,22 @@ const AccountTable: React.FC = ({ list, isFetching }) => { }) } + async function initPrivyWallet(publicAddress: string) { + const t = new Toast('Initializing Privy wallet') + const client = new TradingClient({}, apiUrl) + + try { + const response = await client.trading_InitPrivyWallet(publicAddress) + if (response.success) { + t.update('success', 'Privy wallet initialized successfully') + } else { + t.update('error', `Initialization failed: ${response.error || 'Unknown error'}`) + } + } catch (err) { + t.update('error', 'Error: ' + err) + } + } + const columns = useMemo( () => [ { @@ -114,29 +121,37 @@ const AccountTable: React.FC = ({ list, isFetching }) => { {account.type === AccountType.Privy && ( - - )} + <> + - {account.type === AccountType.Privy && ( - + + + + )} )