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 && (
-
+
+
+
+ >
)}
)