diff --git a/src/Managing.Api/Controllers/TradingController.cs b/src/Managing.Api/Controllers/TradingController.cs index bd053d18..cf465dad 100644 --- a/src/Managing.Api/Controllers/TradingController.cs +++ b/src/Managing.Api/Controllers/TradingController.cs @@ -200,6 +200,49 @@ public class TradingController : BaseController } } + /// + /// Revokes all token approvals for a Privy wallet address. + /// Only admins can revoke approvals for any address, regular users can only revoke approvals for their own addresses. + /// + /// The public address of the Privy wallet to revoke approvals for. + /// The revocation response containing success status and transaction hashes. + [HttpPost("RevokeAllApprovals")] + public async Task> RevokeAllApprovals([FromBody] string publicAddress) + { + if (string.IsNullOrEmpty(publicAddress)) + { + return BadRequest("Public address cannot be null or empty."); + } + + try + { + var user = await GetUser(); + if (user == null) + { + return Unauthorized("User not found"); + } + + // Check if user has permission to revoke approvals for this address + if (!await CanUserInitializeAddress(user.Name, publicAddress)) + { + return Forbid( + "You don't have permission to revoke approvals for this wallet address. You can only revoke approvals for your own wallet addresses."); + } + + var result = await _tradingService.RevokeAllApprovals(publicAddress); + return Ok(result); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error revoking all approvals for Privy wallet address: {Address}", publicAddress); + return StatusCode(500, new Managing.Infrastructure.Evm.Models.Privy.PrivyRevokeAllApprovalsResponse + { + Success = false, + Error = "An error occurred while revoking all approvals for the Privy wallet address." + }); + } + } + /// /// Checks if the user can initialize the given public address. /// Admins can initialize any address, regular users can only initialize their own addresses. diff --git a/src/Managing.Api/appsettings.json b/src/Managing.Api/appsettings.json index 95225bb0..ad88ac95 100644 --- a/src/Managing.Api/appsettings.json +++ b/src/Managing.Api/appsettings.json @@ -28,7 +28,7 @@ }, "Llm": { "Gemini": { - "DefaultModel": "gemini-2.0-flash" + "DefaultModel": "gemini/gemini-3-flash-preview" }, "OpenAI": { "DefaultModel": "gpt-4o" diff --git a/src/Managing.Application.Abstractions/Services/ITradingService.cs b/src/Managing.Application.Abstractions/Services/ITradingService.cs index b31543ff..65026f5a 100644 --- a/src/Managing.Application.Abstractions/Services/ITradingService.cs +++ b/src/Managing.Application.Abstractions/Services/ITradingService.cs @@ -69,6 +69,8 @@ public interface ITradingService DateTime startDate, DateTime endDate, List indicators); + + Task RevokeAllApprovals(string publicAddress); } /// diff --git a/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs b/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs index 1b5254c8..32d99d85 100644 --- a/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs +++ b/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs @@ -41,5 +41,7 @@ namespace Managing.Application.Abstractions.Services string? ticker = null, DateTime? fromDate = null, DateTime? toDate = null); + + Task RevokeAllApprovalsAsync(string address); } } \ No newline at end of file diff --git a/src/Managing.Application/Trading/TradingService.cs b/src/Managing.Application/Trading/TradingService.cs index 11dfac08..19b3de7b 100644 --- a/src/Managing.Application/Trading/TradingService.cs +++ b/src/Managing.Application/Trading/TradingService.cs @@ -542,12 +542,39 @@ public class TradingService : ITradingService // Generate signals for the date range using rolling window approach var signals = GenerateSignalsForDateRange(candlesList, scenario, indicatorsValues); - return new RefineIndicatorsResult + return new RefineIndicatorsResult + { + IndicatorsValues = indicatorsValues, + Signals = signals + }; + } + + public async Task RevokeAllApprovals(string publicAddress) { - IndicatorsValues = indicatorsValues, - Signals = signals - }; - } + try + { + if (string.IsNullOrEmpty(publicAddress)) + { + _logger.LogWarning("Attempted to revoke approvals with null or empty public address"); + return new Managing.Infrastructure.Evm.Models.Privy.PrivyRevokeAllApprovalsResponse + { Success = false, Error = "Public address cannot be null or empty" }; + } + + // Call the Web3ProxyService to revoke all approvals + var result = await _web3ProxyService.RevokeAllApprovalsAsync(publicAddress); + + return result; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error revoking all approvals for address {PublicAddress}", publicAddress); + return new Managing.Infrastructure.Evm.Models.Privy.PrivyRevokeAllApprovalsResponse + { + Success = false, + Error = ex.Message + }; + } + } /// /// Maps IndicatorRequest list to a domain Scenario object. diff --git a/src/Managing.Domain/Evm/PrivyRevokeAllApprovalsResponse.cs b/src/Managing.Domain/Evm/PrivyRevokeAllApprovalsResponse.cs new file mode 100644 index 00000000..c7f366a2 --- /dev/null +++ b/src/Managing.Domain/Evm/PrivyRevokeAllApprovalsResponse.cs @@ -0,0 +1,18 @@ +namespace Managing.Infrastructure.Evm.Models.Privy; + +public class PrivyRevokeAllApprovalsResponse +{ + public bool Success { get; set; } + public string? OrderVaultUsdcHash { get; set; } + public string? OrderVaultWethHash { get; set; } + public string? ExchangeRouterUsdcHash { get; set; } + public string? ExchangeRouterWethHash { get; set; } + public string? SyntheticsRouterUsdcHash { get; set; } + public string? SyntheticsRouterWethHash { get; set; } + public string? DataStoreUsdcHash { get; set; } + public string? DataStoreWethHash { get; set; } + public string? DepositVaultUsdcHash { get; set; } + public string? DepositVaultWethHash { get; set; } + public string? Error { get; set; } +} + diff --git a/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs b/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs index c0d29841..cc740417 100644 --- a/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs +++ b/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs @@ -819,5 +819,19 @@ namespace Managing.Infrastructure.Evm.Services return positions; } + + public async Task RevokeAllApprovalsAsync(string address) + { + var payload = new { address }; + + var response = await CallPrivyServiceAsync("/revoke-all-approvals", payload); + + if (response == null) + { + throw new Web3ProxyException("Revoke all approvals response is null"); + } + + return response; + } } } \ No newline at end of file diff --git a/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts b/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts index d7c51156..a7045f98 100644 --- a/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts +++ b/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts @@ -1444,40 +1444,6 @@ export interface JobStatusTypeSummary { count?: number; } -export interface LlmProgressUpdate { - type?: string; - message?: string; - iteration?: number | null; - maxIterations?: number | null; - toolName?: string | null; - toolArguments?: { [key: string]: any; } | null; - content?: string | null; - response?: LlmChatResponse | null; - error?: string | null; - timestamp?: Date; -} - -export interface LlmChatResponse { - content?: string; - provider?: string; - model?: string; - toolCalls?: LlmToolCall[] | null; - usage?: LlmUsage | null; - requiresToolExecution?: boolean; -} - -export interface LlmToolCall { - id?: string; - name?: string; - arguments?: { [key: string]: any; }; -} - -export interface LlmUsage { - promptTokens?: number; - completionTokens?: number; - totalTokens?: number; -} - export interface LlmChatRequest { messages?: LlmMessage[]; provider?: string | null; @@ -1488,6 +1454,10 @@ export interface LlmChatRequest { tools?: McpToolDefinition[] | null; } +export interface LlmChatStreamRequest extends LlmChatRequest { + connectionId?: string | null; +} + export interface LlmMessage { role?: string; content?: string; @@ -1495,6 +1465,12 @@ export interface LlmMessage { toolCallId?: string | null; } +export interface LlmToolCall { + id?: string; + name?: string; + arguments?: { [key: string]: any; }; +} + export interface McpToolDefinition { name?: string; description?: string; @@ -1508,6 +1484,21 @@ export interface McpParameterDefinition { defaultValue?: any | null; } +export interface LlmChatResponse { + content?: string; + provider?: string; + model?: string; + toolCalls?: LlmToolCall[] | null; + usage?: LlmUsage | null; + requiresToolExecution?: boolean; +} + +export interface LlmUsage { + promptTokens?: number; + completionTokens?: number; + totalTokens?: number; +} + export interface ScenarioViewModel { name: string; indicators: IndicatorViewModel[]; @@ -1548,6 +1539,21 @@ export interface PrivyInitAddressResponse { isAlreadyInitialized?: boolean; } +export interface PrivyRevokeAllApprovalsResponse { + success?: boolean; + orderVaultUsdcHash?: string | null; + orderVaultWethHash?: string | null; + exchangeRouterUsdcHash?: string | null; + exchangeRouterWethHash?: string | null; + syntheticsRouterUsdcHash?: string | null; + syntheticsRouterWethHash?: string | null; + dataStoreUsdcHash?: string | null; + dataStoreWethHash?: string | null; + depositVaultUsdcHash?: string | null; + depositVaultWethHash?: string | null; + error?: string | null; +} + export interface IndicatorRequestDto { indicatorName: string; strategyDescription: string; diff --git a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts index 70ae74a7..2e771b78 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts @@ -45,6 +45,7 @@ declare module 'fastify' { signPrivyMessage: typeof signPrivyMessage; approveToken: typeof approveToken; initAddress: typeof initAddress; + revokeAllApprovals: typeof revokeAllApprovals; sendToken: typeof sendToken; getWalletBalance: typeof getWalletBalance; getTokenBalanceOnChain: typeof getTokenBalanceOnChain; @@ -975,6 +976,277 @@ export async function initAddress( } } +/** + * Revokes all token approvals for an address by setting approvals to 0 for all GMX contracts + * @param address The wallet address to revoke approvals for + * @returns Object containing transaction hashes for all revoked approvals + */ +export const revokeAllApprovalsImpl = async ( + address: string, + fastify?: FastifyInstance +): Promise<{ + orderVaultUsdcHash: string, + orderVaultWethHash: string, + exchangeRouterUsdcHash: string, + exchangeRouterWethHash: string, + syntheticsRouterUsdcHash: string, + syntheticsRouterWethHash: string, + dataStoreUsdcHash: string, + dataStoreWethHash: string, + depositVaultUsdcHash: string, + depositVaultWethHash: string +}> => { + try { + console.log('🚫 Starting revocation of all approvals for address:', address); + + const sdk = await getClientForAddress(address); + const {tokensData} = await sdk.tokens.getTokensData(); + const usdcTokenData = getTokenDataFromTicker(Ticker.USDC, tokensData); + const wrapperEtherData = getTokenDataFromTicker("WETH", tokensData); + + // Revoke by setting approval to 0 + const revokeAmount = BigInt(0); + console.log('šŸ“Š Revocation amount set to:', revokeAmount.toString()); + + // Get USDC and WETH token addresses + const usdcToken = GetToken('USDC'); + console.log('šŸ’± USDC Token Address:', usdcToken.address); + console.log('šŸ’± WETH Token Address:', wrapperEtherData.address); + + const results: any = {}; + + // ============================================================================ + // Revoke OrderVault Approvals + // ============================================================================ + console.log('\nšŸ” Step 1: Revoking OrderVault approvals...'); + + // USDC approval for OrderVault + console.log(' Revoking USDC -> OrderVault approval...'); + results.orderVaultUsdcHash = await approveContractImpl( + address, + usdcToken.address, + CONTRACTS[ARBITRUM].OrderVault, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… USDC OrderVault revocation hash:', results.orderVaultUsdcHash); + + // WETH approval for OrderVault + console.log(' Revoking WETH -> OrderVault approval...'); + results.orderVaultWethHash = await approveContractImpl( + address, + wrapperEtherData.address, + CONTRACTS[ARBITRUM].OrderVault, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… WETH OrderVault revocation hash:', results.orderVaultWethHash); + + // ============================================================================ + // Revoke ExchangeRouter Approvals + // ============================================================================ + console.log('\nšŸ” Step 2: Revoking ExchangeRouter approvals...'); + + // USDC approval for ExchangeRouter + console.log(' Revoking USDC -> ExchangeRouter approval...'); + results.exchangeRouterUsdcHash = await approveContractImpl( + address, + usdcToken.address, + CONTRACTS[ARBITRUM].ExchangeRouter, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… USDC ExchangeRouter revocation hash:', results.exchangeRouterUsdcHash); + + // WETH approval for ExchangeRouter + console.log(' Revoking WETH -> ExchangeRouter approval...'); + results.exchangeRouterWethHash = await approveContractImpl( + address, + wrapperEtherData.address, + CONTRACTS[ARBITRUM].ExchangeRouter, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… WETH ExchangeRouter revocation hash:', results.exchangeRouterWethHash); + + // ============================================================================ + // Revoke SyntheticsRouter Approvals + // ============================================================================ + console.log('\nšŸ” Step 3: Revoking SyntheticsRouter approvals...'); + + // USDC approval for SyntheticsRouter + console.log(' Revoking USDC -> SyntheticsRouter approval...'); + results.syntheticsRouterUsdcHash = await approveContractImpl( + address, + usdcToken.address, + CONTRACTS[ARBITRUM].SyntheticsRouter, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… USDC SyntheticsRouter revocation hash:', results.syntheticsRouterUsdcHash); + + // WETH approval for SyntheticsRouter + console.log(' Revoking WETH -> SyntheticsRouter approval...'); + results.syntheticsRouterWethHash = await approveContractImpl( + address, + wrapperEtherData.address, + CONTRACTS[ARBITRUM].SyntheticsRouter, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… WETH SyntheticsRouter revocation hash:', results.syntheticsRouterWethHash); + + // ============================================================================ + // Revoke DataStore Approvals + // ============================================================================ + console.log('\nšŸ” Step 4: Revoking DataStore approvals...'); + + // USDC approval for DataStore + console.log(' Revoking USDC -> DataStore approval...'); + results.dataStoreUsdcHash = await approveContractImpl( + address, + usdcToken.address, + CONTRACTS[ARBITRUM].DataStore, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… USDC DataStore revocation hash:', results.dataStoreUsdcHash); + + // WETH approval for DataStore + console.log(' Revoking WETH -> DataStore approval...'); + results.dataStoreWethHash = await approveContractImpl( + address, + wrapperEtherData.address, + CONTRACTS[ARBITRUM].DataStore, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… WETH DataStore revocation hash:', results.dataStoreWethHash); + + // ============================================================================ + // Revoke DepositVault Approvals + // ============================================================================ + console.log('\nšŸ” Step 5: Revoking DepositVault approvals...'); + + // USDC approval for DepositVault + console.log(' Revoking USDC -> DepositVault approval...'); + results.depositVaultUsdcHash = await approveContractImpl( + address, + usdcToken.address, + CONTRACTS[ARBITRUM].DepositVault, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… USDC DepositVault revocation hash:', results.depositVaultUsdcHash); + + // WETH approval for DepositVault + console.log(' Revoking WETH -> DepositVault approval...'); + results.depositVaultWethHash = await approveContractImpl( + address, + wrapperEtherData.address, + CONTRACTS[ARBITRUM].DepositVault, + ARBITRUM, + revokeAmount, + true, + fastify + ); + console.log(' āœ… WETH DepositVault revocation hash:', results.depositVaultWethHash); + + // ============================================================================ + // SUMMARY: Final revocation status + // ============================================================================ + console.log('\nšŸ“‹ Final Revocation Summary:'); + console.log(' OrderVault USDC:', results.orderVaultUsdcHash); + console.log(' OrderVault WETH:', results.orderVaultWethHash); + console.log(' ExchangeRouter USDC:', results.exchangeRouterUsdcHash); + console.log(' ExchangeRouter WETH:', results.exchangeRouterWethHash); + console.log(' SyntheticsRouter USDC:', results.syntheticsRouterUsdcHash); + console.log(' SyntheticsRouter WETH:', results.syntheticsRouterWethHash); + console.log(' DataStore USDC:', results.dataStoreUsdcHash); + console.log(' DataStore WETH:', results.dataStoreWethHash); + console.log(' DepositVault USDC:', results.depositVaultUsdcHash); + console.log(' DepositVault WETH:', results.depositVaultWethHash); + + // Clear approval cache for this address since all approvals have been revoked + try { + const {clearApprovalCacheForAccount} = await import('../../utils/approvalCache.js'); + await clearApprovalCacheForAccount(ARBITRUM, address); + console.log(' āœ… Approval cache cleared for address'); + } catch (cacheError) { + console.warn(' āš ļø Failed to clear approval cache:', cacheError); + // Don't fail the entire operation if cache clearing fails + } + + console.log('\nāœ… All approvals revoked successfully!'); + + return results; + } catch (error) { + console.error('āŒ Error revoking approvals:', error); + throw new Error(`Failed to revoke approvals: ${error instanceof Error ? error.message : 'Unknown error'}`); + } +}; + +/** + * Revokes all token approvals for a wallet address + * @param this The FastifyRequest instance + * @param reply The FastifyReply instance + * @param address The wallet address to revoke approvals for + * @returns The response object with success status and transaction hashes + */ +export async function revokeAllApprovals( + this: FastifyRequest, + reply: FastifyReply, + address: string +) { + try { + if (!address) { + throw new Error('Wallet address is required for revocation'); + } + + const results = await revokeAllApprovalsImpl(address, this.server); + + return { + success: true, + orderVaultUsdcHash: results.orderVaultUsdcHash, + orderVaultWethHash: results.orderVaultWethHash, + exchangeRouterUsdcHash: results.exchangeRouterUsdcHash, + exchangeRouterWethHash: results.exchangeRouterWethHash, + syntheticsRouterUsdcHash: results.syntheticsRouterUsdcHash, + syntheticsRouterWethHash: results.syntheticsRouterWethHash, + dataStoreUsdcHash: results.dataStoreUsdcHash, + dataStoreWethHash: results.dataStoreWethHash, + depositVaultUsdcHash: results.depositVaultUsdcHash, + depositVaultWethHash: results.depositVaultWethHash + }; + } catch (error) { + this.log.error(error); + + reply.status(500); + return { + success: false, + error: error instanceof Error ? error.message : 'An unknown error occurred' + }; + } +} + /** * Sends tokens from one address to another using Privy wallet (implementation) * @param senderAddress The sender's wallet address @@ -1756,6 +2028,10 @@ export default fp(async (fastify) => { return initAddress.call(this, reply, address); }); + fastify.decorateRequest('revokeAllApprovals', async function(this: FastifyRequest, reply: FastifyReply, address: string) { + return revokeAllApprovals.call(this, reply, address); + }); + fastify.decorateRequest('sendToken', async function(this: FastifyRequest, reply: FastifyReply, senderAddress: string, recipientAddress: string, ticker: string, amount: string, chainId?: number) { return sendToken.call(this, reply, senderAddress, recipientAddress, ticker, amount, chainId); }); diff --git a/src/Managing.Web3Proxy/src/routes/api/privy/index.ts b/src/Managing.Web3Proxy/src/routes/api/privy/index.ts index a046db80..3f3db7c8 100644 --- a/src/Managing.Web3Proxy/src/routes/api/privy/index.ts +++ b/src/Managing.Web3Proxy/src/routes/api/privy/index.ts @@ -77,6 +77,50 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => { } ) + fastify.post( + '/revoke-all-approvals', + { + schema: { + body: Type.Object({ + address: Type.String() + }), + response: { + 200: Type.Object({ + success: Type.Boolean(), + orderVaultUsdcHash: Type.Optional(Type.String()), + orderVaultWethHash: Type.Optional(Type.String()), + exchangeRouterUsdcHash: Type.Optional(Type.String()), + exchangeRouterWethHash: Type.Optional(Type.String()), + syntheticsRouterUsdcHash: Type.Optional(Type.String()), + syntheticsRouterWethHash: Type.Optional(Type.String()), + dataStoreUsdcHash: Type.Optional(Type.String()), + dataStoreWethHash: Type.Optional(Type.String()), + depositVaultUsdcHash: Type.Optional(Type.String()), + depositVaultWethHash: Type.Optional(Type.String()), + error: Type.Optional(Type.String()) + }), + 400: Type.Object({ + success: Type.Boolean(), + error: Type.String() + }), + 500: Type.Object({ + success: Type.Boolean(), + error: Type.String() + }) + }, + tags: ['Privy'] + } + }, + async function (request, reply) { + try { + const { address } = request.body; + return await request.revokeAllApprovals(reply, address); + } catch (error) { + return handleError(request, reply, error, 'privy/revoke-all-approvals'); + } + } + ) + fastify.post( '/send-token', { diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts index a6035a36..6339892f 100644 --- a/src/Managing.WebApp/src/generated/ManagingApi.ts +++ b/src/Managing.WebApp/src/generated/ManagingApi.ts @@ -2910,7 +2910,7 @@ export class LlmClient extends AuthorizedApiBase { this.baseUrl = baseUrl ?? "http://localhost:5000"; } - llm_ChatStream(request: LlmChatRequest): Promise { + llm_ChatStream(request: LlmChatStreamRequest): Promise { let url_ = this.baseUrl + "/Llm/ChatStream"; url_ = url_.replace(/[?&]$/, ""); @@ -2921,7 +2921,7 @@ export class LlmClient extends AuthorizedApiBase { method: "POST", headers: { "Content-Type": "application/json", - "Accept": "application/json" + "Accept": "application/octet-stream" } }; @@ -2932,21 +2932,26 @@ export class LlmClient extends AuthorizedApiBase { }); } - protected processLlm_ChatStream(response: Response): Promise { + protected processLlm_ChatStream(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 LlmProgressUpdate[]; - return result200; - }); + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined; + let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined; + if (fileName) { + fileName = decodeURIComponent(fileName); + } else { + fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + } + return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); } 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); + return Promise.resolve(null as any); } llm_Chat(request: LlmChatRequest): Promise { @@ -4262,6 +4267,45 @@ export class TradingClient extends AuthorizedApiBase { return Promise.resolve(null as any); } + trading_RevokeAllApprovals(publicAddress: string): Promise { + let url_ = this.baseUrl + "/Trading/RevokeAllApprovals"; + 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_RevokeAllApprovals(_response); + }); + } + + protected processTrading_RevokeAllApprovals(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 PrivyRevokeAllApprovalsResponse; + 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); + } + trading_RequestIndicator(request: IndicatorRequestDto): Promise { let url_ = this.baseUrl + "/Trading/RequestIndicator"; url_ = url_.replace(/[?&]$/, ""); @@ -6272,40 +6316,6 @@ export interface JobStatusTypeSummary { count?: number; } -export interface LlmProgressUpdate { - type?: string; - message?: string; - iteration?: number | null; - maxIterations?: number | null; - toolName?: string | null; - toolArguments?: { [key: string]: any; } | null; - content?: string | null; - response?: LlmChatResponse | null; - error?: string | null; - timestamp?: Date; -} - -export interface LlmChatResponse { - content?: string; - provider?: string; - model?: string; - toolCalls?: LlmToolCall[] | null; - usage?: LlmUsage | null; - requiresToolExecution?: boolean; -} - -export interface LlmToolCall { - id?: string; - name?: string; - arguments?: { [key: string]: any; }; -} - -export interface LlmUsage { - promptTokens?: number; - completionTokens?: number; - totalTokens?: number; -} - export interface LlmChatRequest { messages?: LlmMessage[]; provider?: string | null; @@ -6316,6 +6326,10 @@ export interface LlmChatRequest { tools?: McpToolDefinition[] | null; } +export interface LlmChatStreamRequest extends LlmChatRequest { + connectionId?: string | null; +} + export interface LlmMessage { role?: string; content?: string; @@ -6323,6 +6337,12 @@ export interface LlmMessage { toolCallId?: string | null; } +export interface LlmToolCall { + id?: string; + name?: string; + arguments?: { [key: string]: any; }; +} + export interface McpToolDefinition { name?: string; description?: string; @@ -6336,6 +6356,21 @@ export interface McpParameterDefinition { defaultValue?: any | null; } +export interface LlmChatResponse { + content?: string; + provider?: string; + model?: string; + toolCalls?: LlmToolCall[] | null; + usage?: LlmUsage | null; + requiresToolExecution?: boolean; +} + +export interface LlmUsage { + promptTokens?: number; + completionTokens?: number; + totalTokens?: number; +} + export interface ScenarioViewModel { name: string; indicators: IndicatorViewModel[]; @@ -6376,6 +6411,21 @@ export interface PrivyInitAddressResponse { isAlreadyInitialized?: boolean; } +export interface PrivyRevokeAllApprovalsResponse { + success?: boolean; + orderVaultUsdcHash?: string | null; + orderVaultWethHash?: string | null; + exchangeRouterUsdcHash?: string | null; + exchangeRouterWethHash?: string | null; + syntheticsRouterUsdcHash?: string | null; + syntheticsRouterWethHash?: string | null; + dataStoreUsdcHash?: string | null; + dataStoreWethHash?: string | null; + depositVaultUsdcHash?: string | null; + depositVaultWethHash?: string | null; + error?: string | null; +} + export interface IndicatorRequestDto { indicatorName: string; strategyDescription: string; diff --git a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts index d7c51156..a7045f98 100644 --- a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts +++ b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts @@ -1444,40 +1444,6 @@ export interface JobStatusTypeSummary { count?: number; } -export interface LlmProgressUpdate { - type?: string; - message?: string; - iteration?: number | null; - maxIterations?: number | null; - toolName?: string | null; - toolArguments?: { [key: string]: any; } | null; - content?: string | null; - response?: LlmChatResponse | null; - error?: string | null; - timestamp?: Date; -} - -export interface LlmChatResponse { - content?: string; - provider?: string; - model?: string; - toolCalls?: LlmToolCall[] | null; - usage?: LlmUsage | null; - requiresToolExecution?: boolean; -} - -export interface LlmToolCall { - id?: string; - name?: string; - arguments?: { [key: string]: any; }; -} - -export interface LlmUsage { - promptTokens?: number; - completionTokens?: number; - totalTokens?: number; -} - export interface LlmChatRequest { messages?: LlmMessage[]; provider?: string | null; @@ -1488,6 +1454,10 @@ export interface LlmChatRequest { tools?: McpToolDefinition[] | null; } +export interface LlmChatStreamRequest extends LlmChatRequest { + connectionId?: string | null; +} + export interface LlmMessage { role?: string; content?: string; @@ -1495,6 +1465,12 @@ export interface LlmMessage { toolCallId?: string | null; } +export interface LlmToolCall { + id?: string; + name?: string; + arguments?: { [key: string]: any; }; +} + export interface McpToolDefinition { name?: string; description?: string; @@ -1508,6 +1484,21 @@ export interface McpParameterDefinition { defaultValue?: any | null; } +export interface LlmChatResponse { + content?: string; + provider?: string; + model?: string; + toolCalls?: LlmToolCall[] | null; + usage?: LlmUsage | null; + requiresToolExecution?: boolean; +} + +export interface LlmUsage { + promptTokens?: number; + completionTokens?: number; + totalTokens?: number; +} + export interface ScenarioViewModel { name: string; indicators: IndicatorViewModel[]; @@ -1548,6 +1539,21 @@ export interface PrivyInitAddressResponse { isAlreadyInitialized?: boolean; } +export interface PrivyRevokeAllApprovalsResponse { + success?: boolean; + orderVaultUsdcHash?: string | null; + orderVaultWethHash?: string | null; + exchangeRouterUsdcHash?: string | null; + exchangeRouterWethHash?: string | null; + syntheticsRouterUsdcHash?: string | null; + syntheticsRouterWethHash?: string | null; + dataStoreUsdcHash?: string | null; + dataStoreWethHash?: string | null; + depositVaultUsdcHash?: string | null; + depositVaultWethHash?: string | null; + error?: string | null; +} + export interface IndicatorRequestDto { indicatorName: string; strategyDescription: string; diff --git a/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx b/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx index 4901b36d..13e92c0b 100644 --- a/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx +++ b/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx @@ -1,7 +1,7 @@ import {ChevronDownIcon, ChevronRightIcon,} from '@heroicons/react/solid' import React, {useEffect, useMemo, useState} from 'react' import {useNavigate} from 'react-router-dom' -import {FiCopy, FiKey, FiPlay, FiTrash2, FiTrendingUp} from 'react-icons/fi' +import {FiCopy, FiKey, FiPlay, FiTrash2, FiTrendingUp, FiX} from 'react-icons/fi' import useApiUrlStore from '../../../app/store/apiStore' import {SelectColumnFilter, Table, Toast,} from '../../../components/mollecules' @@ -55,6 +55,22 @@ const AccountTable: React.FC = ({ list, isFetching }) => { } } + async function revokeAllApprovals(publicAddress: string) { + const t = new Toast('Revoking all approvals') + const client = new TradingClient({}, apiUrl) + + try { + const response = await client.trading_RevokeAllApprovals(publicAddress) + if (response.success) { + t.update('success', 'All approvals revoked successfully') + } else { + t.update('error', `Revocation failed: ${response.error || 'Unknown error'}`) + } + } catch (err) { + t.update('error', 'Error: ' + err) + } + } + async function copyToClipboard(text: string) { const t = new Toast('Copying to clipboard...') try { @@ -160,6 +176,14 @@ const AccountTable: React.FC = ({ list, isFetching }) => { Init + + + +